Hi everyone Isn’t it dangerous to use the variabl...
# fw1
c
Hi everyone Isn’t it dangerous to use the variables scope in components that have been cached in the Application scope? It seems that by default, all FW1 services are singletons? Here is a bit more detail about what I mean. I am using FW1 and I have just found out that controllers and services are singletons [application scope]: https://framework-one.github.io/documentation/4.3/developing-applications/#services-domain-objects-and-persistence Inside one of my controllers, I have made two method calls: blogController
Copy code
function list(rc){
    rc.page = 1;
    variables.blogService.page(rc.page);
    rc.data = variables.blogService.list();
}
blogService
Copy code
component accessors = true{
    variables.blogs = {};

    // constructor etc…
 
    function page(page){
        // build variables.blogs struct from DB query
    }
 
    function list(){
        return variables.blogs;
    }
}
So, essentially, the
blogService
page method uses a DB query to populate:
Copy code
variables.blogs
And then I immediately return this variable, in the
list()
method. What worries me, is that if there are two different requests like: REQUEST 1:
Copy code
rc.page = 1;
variables.blogService.page(rc.page);
rc.data = variables.blogService.list();
REQUEST 2:
Copy code
rc.page = 2;
variables.blogService.page(rc.page);
rc.data = variables.blogService.list();
The list data might get mixed up? My question: Are the two method calls, atomic, in the
blogController
, per request? I know that Coldfusion is multi-threaded, so requests are dealth with, in parallel. I am worried that the following might happen:
Copy code
REQUEST 1 rc.page = 1;
REQUEST 1 variables.blogService.page(rc.page);
REQUEST 2 rc.page = 2;
REQUEST 2 variables.blogService.page(rc.page);
REQUEST 1 rc.data = variables.blogService.list();
REQUEST 2 rc.data = variables.blogService.list();
Essentially, the user responsible for REQUEST 1 will receive the REQUEST 2 data. I feel that data is safe, within a singleton, as long as methods are UDFs [functional/stateless methods], but when there is stateful data, in a singleton, then the alarm bells start ringing. I am not sure why I decided to create a component variables variable, but I think I found it in an FW1 example. The three potential solutions I have, are: 1) Make services instances, not singletons [remove from the application scope] CANNOT DO THIS AS FW1 THROWS AN ERROR 2) Lock the two method calls, like:
Copy code
cflock (name="listBlogService", type="exclusive", timeout="30") {
    variables.blogService.page(rc.page);
    rc.data = variables.blogService.list();
}
3) Remove the
blogService
list()
method and return the list from the
page()
method. This would turn the
page()
method into a UDF, removing references to state. I am veering towards option 3?
w
the flaw is in the use of the variables scope for dynamic or state data. services are singletons as you noted, and anything you store in the variables scope IS going to be shared by any given request.
it's unclear why you're storing/returning 'blogs' data from the variables scope, the purpose of those methods isn't entirely clear
m
@Charles Robertson yes, the approach that you have could result in data being crossed. I'd use an approach more in line with option 3, using the rc.page as an argument. An alternative approach would be to have a transient page component (in /beans) that has the rc.page set in its variables scope. It would then reach into the service to retrieve and return the list:
Copy code
rc.page = 1
var pageBean = variables.beanFactory.getBean("pageBean");
pageBean.setId(rc.page);
rc.data = pageBean.list();

//within pageBean
list(){
return variables.pageService.list(pageId = variables.id );
}
That code could be cleaned up, obviously, but it's a rough idea
👍 1
c
Thanks for confirming my suspicions. I think I will use solution 3.
Yes. Thanks. I actually copied the
variables
approach from an example FW1 app, a long time ago. But, I think I misunderstood the intention of the example. I think the original intention was to build up a Struct of blog beans, so that data could be cached, rather than having to fetch it from the DB, every time. Over time, more blog beans would get added to the Struct by many different users etc. But, my objective is completely different. I want to create small pagination lists, so the previous objective is completely inappropriate. I will use OPTION 3, and return the list data directly from the
page()
method.
👍 1