I am having some concurrency issues in cfwheels.
I have some code in events/onrequeststart.cfm that is being executed every time the user is requesting something.
Test case:
User A - request time: 10sec
User B - request time: 2sec
If the user B issues a request while the user A is already working on a request, user's B settings will go into user A and user A will display results based on user's B request.
I tried using cflock on the onrequeststart.cfm but it doesn't seem to work. I don't have much experience with cfwheels so I maybe trying to do something that is logically wrong.
This is part of the code that gets confused.
<cfquery name="currentUser" datasource="#application.ds#">
select * from clientadmin where clientAdminid ='#session.clientadminid#'
</cfquery>
<cfquery name="currentClient" datasource="#application.ds#">
select * from clientBrands where clientbrandID ='#currentUser.ClientBrandID#'
</cfquery>
<cfset application.clientAdminSurveys = application.generalFunctions.clientSurveys(clientAdminID=session.clientAdminID, clientBrandID = currentUser.clientBrandID)>
<cfset application.AssociatedDoctors = application.generalFunctions.AssociatedDoctors(clientAdminID=session.clientAdminID, clientBrandID = currentUser.clientBrandID)>
So, I guess my question is, how to avoid this from happening?
1) The Application scope is "application wide" (all users of site wide) - you shouldn't be setting per user settings there, ever, as as you've discovered, user B overwrites user A. Use the session scope for per user stuff. So in your last two lines you're setting application scope stuff using session scope data!
2) As a side note, in wheels you can use application.wheels.datasourcename to get the database name
I would put that code into a function inside the controller(controller.cfc) and run it using a filter.
see: http://cfwheels.org/docs/1-1/chapter/filters
This has worked for me without issues for similar tasks.
Also I would drop any reference to application. because that's likely where items are getting mixed up. The correct place to put these functions is into events/functions.cfm
of course this is without seeing more of your code...
As mentioned by Neokoenig, you are utilizing a shared scope to store user specific data, you should store that in SESSION. If you need the data in application scope you should be using a lock while setting that data, but it looks like you should be running this in onSessionStart once and not on every request. If you need to run it on every request you may want to continue using the onRequestStart but utilize the user specific session storage and not the global application layer.
Just remember:
Application variables will show the same data for all users. So if user a sets application.foo = 1 and user b sets application.foo = 2 then user one try to access application.foo, user 1 will see user 2's value of 2. If this was using session scope you would not have this same issue. If user 1 sets SESSION.foo = 1 and user 2 sets SESSION.foo = 2. When the user accesses the SESSION.foo variable it will only contain the data set by that user (ex: user 1 will output SESSION.foo and see the value, 1)
Related
I have a script :
<cfscript>
gf = createObject('component','com.general');
gf.checkIpBlocked();
</cfscript>
that I want to fire onSessionStart.
I added an onSessionStart to /siteID/includes/themes/myTheme/eventHandler.cfc. But the session start NEVER fires. I know there is something managing sessions because of I open the admin, login then close the browser, re-open it I am forced to login again.
If I set a session variable close the browser and and the session.testVar never goes away and seems to hold the initial value for a very long time.
I am not trying to manage mura users or anything I am just trying to set a session variable the first time in a "session". In a typical application.cfc this is easy.
Any insight is appreciated.
Unfortunately, that's a bug. However, one thing to keep in mind is that onSiteSessionStart is unreliable since it only fires when a siteID is defined within the request. For example, if you were to go to the admin and be asked to login your session will have started and there would have been no siteID.
For now I would try using onSiteRequestStart to param the variable instead.
function onSiteRequestStart($){
param name="session.ipChecked" default=false;
if(!session.ipChecked){
var gf = createObject('component','com.general');
gf.checkIpBlocked();
session.ipChecked=true;
}
}
In regard to our documentation we have three Mura 6 books available both printed and digital downloads from Lulu
And are also working to create a systematic way to post the contents of those books on our support site which we are hoping to complete by MuraCon on 9/30. So that the all of our documentation will stay update and in sync.
The Mura docs state that the application events are actually onGlobalSessionStart and/or onSiteSessionStart.
Application Events
onApplicationLoad onSiteSessionStart
onGlobalSessionStart onSiteSessionEnd
onSiteMissingTemplate onSiteError
onGlobalError onBeforeAutoUpdate
onAfterAutoUpdate onGlobalThreatDetect
Note that Events that begin with onGlobal are deļ¬ned on a per-Mura
instance basis.
Mura docs.
I have an Instagram application written in Coldfusion 8 that basically pulls in media by tags and then allows people to Like / vote on the photos which is all done via the Instagram API. The Liking part is causing me no end of grief though, as I can get the Authentication and Access_Token without a drama, however the Access_Token doesn't appear to have permission to Like by default. There is an optional param for the Authenticate call "scope" which allows you to pass the permissions allowed for the Access_Token but i cannot work out how to pass this via ColdFusion CFHTTP as a POST.
Here is the preparation for the data to be sent over CFHTTP looping over all params as type="FormField". No matter how I try and present the scope options, either JSON format, string with spaces, string with "+" delimiters it seems to have no effect and the Like operation continues to fail due to permission errors.
<cfscript>
var LOCAL = {};
LOCAL['config'] = {};
LOCAL['returnStruct'] = {};
// prep packet required by the main call method
// the following values are required for EVERY call
LOCAL['config']['method'] = 'POST';
LOCAL['config']['format'] = ARGUMENTS['outputType'];
LOCAL['config']['url'] = VARIABLES.authURL;
// variables required by this method
LOCAL['config']['params'] = {};
LOCAL['config']['params']['client_secret'] = ARGUMENTS.client_secret;
LOCAL['config']['params']['grant_type'] = 'authorization_code';
LOCAL['config']['params']['redirect_uri'] = ARGUMENTS.redirect_uri;
LOCAL['config']['params']['code'] = ARGUMENTS.code;
LOCAL['config']['params']['scope'] = 'likes comments relationships';
</cfscript>
If anyone else is running into the same issues with "scope" not being correctly applied to the return Access_Token it turns out the problem was Instagram Documentation being vague about where this argument should be used. I had tried it every way possible as a POST operation as it suggested during the server-side Authentication, however it appears to only work if sent as GET params and after some playing around I decided to tack the "scope" param onto the 2nd stage of the authentication which is where the Code is requested and that worked! See below
https://api.instagram.com/oauth/authorize/?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=likes+basic
This will present the user with an confirmation message from Instagram to allow the application to perform Likes on behalf of the user and everything else works like a charm after this.
I have a shopping cart like application running on SharePoint 2007.
I'm running a very standard update procedure on a list item:
using (SPWeb web = site.OpenWeb())
{
web.AllowUnsafeUpdates = true;
SPList list = web.Lists["Quotes"];
SPListItem item = list.GetItemById(_id);
item["Title"] = _quotename;
item["RecipientName"] = _quotename;
item["RecipientEmail"] = recipientemail;
item["IsActive"] = true;
item.Update();
site.Dispose();
}
This item updates properly, however it briefly appears as modified by System Account. If I wait a second and refresh the page, it shows up again as modified by CurrentUser.
This is an issue because on Page_Load I am retrieving the item that is marked as Active AND is listed as Modified By the CurrentUser. This means as a user updates his list, when the PostBack finishes, it shows he has no active items.
Is it the web.AllowUnsafeUpdates? This is necessary because I was getting a security error before.
What am I missing?
First off, it's not AllowUnsafeUpdates. This simply allows modifying of items from your code.
It's a bit hard to tell what's going on without understanding more of the flow of your application. I would suggest though that using Modified By to associate an item to a user may not be a great idea. This means, as you have discovered, that any modification by the system or even potentially an administrator will break that link.
I would store the current user in a custom field. That should solve your problem and would be a safer design choice.
There could be some other code running in Event Receivers and updating the item. Because event recievers runs in context of system user account, and if you update item from event reciever, the modified field will show just that: the system account has modified the item.
My question seems to be related to this one:
Coldfusion memcached connections
however, i have been unable to solve it.
if i put this code in application.cfm:
<cfif not IsDefined("application.memcached")>
<cfset application.memcachedFactory = createObject("component","memcachedFactory").init("192.168.2.91:11211")>
<cfset application.memcached = application.memcachedFactory.getmemcached()>
</cfif>
the page will work for maybe 270 calls. then it will start to fail with an error "Object Instantiation Exception " The code is properly talking to memcached. I can send and receive data. it seems like java is running out of something .. threads, sockets, handles of some sort. I know little about java, and am stuck.
This seems wrong to me Don. Why would this code run again after the very first call? It should be running 1 time after which you have a reference to your object. What does the rest of your application.cfm look like? Have you added a cfapplication tag with a "name"?
If you fail to set an application "name" (via the cfapplication tag or "this.name" in application.cfc), the an "application.x" variable is treated just like a regular variable. After the page request ends it will "go away" and require the next request to reinstantiate the object over again.
The purpose of the "isDefined()" in this case is to insure it runs only once - providing you with a singleton (single reference) you can use again and again without reinstantiating it. It sounds like you are not "inside" an application.
For my Flash Builder 4.6 Project I have a http service defined which looks at a url from our website.
What I'd like to be able to do though is to change the web service url on the fly within the app. i.e. using the existing url as default but having an admin/settings screen to change where the web service points (either stored in our sqlite database or in local memory).
This would be so that we could allow our customers to host their own version of the website/database but still be able to use/download the app through the app stores.
Has anyone had any experience with doing this?
EDIT: Adding some more details after the comments below.
When I created the HTTP Service through the FlashBuilder wizard it creates two web service classes a super class and a sub class which inherits from the super class. All of the code that the wizard populates goes into the super class.
I can assume that the code I need to put in would be in the sub class. But I do not know which function I'd put it in or how.
Below is a sample of the Super's constructor:
// initialize service control
_serviceControl = new mx.rpc.http.HTTPMultiService("websitehere");
var operations:Array = new Array();
var operation:mx.rpc.http.Operation;
var argsArray:Array;
operation = new mx.rpc.http.Operation(null, "loginRequest");
operation.url = "login.php";
operation.method = "GET";
argsArray = new Array("un","pw");
operation.argumentNames = argsArray;
operation.serializationFilter = serializer0;
operation.properties = new Object();
operation.properties["xPath"] = "/";
operation.contentType = "application/x-www-form-urlencoded";
operation.resultType = valueObjects.Data;
operations.push(operation);
_serviceControl.operationList = operations;
I'm not sure what property of the _serviceControl variable I would need to alter.
Also when I search for my website in my code it brings back a .fml file inside a .model directory which seems to get auto refreshed if I change the service url through the wizard. Would this not cause an issue?
I then have the challenge of accessing the user defined url. Within the app we use an sqlite database to store data but I think it would probably be better to use a 'SharedObject' which we also use to know what account they are logged into. How reliable is this? I assume I would be able to access this via the Service?
Though the awkward thing is that we were planning to have this configurable on a settings screen that would have been accessed after logging in. But to log in it would already need to know which server to point to.
if im reading your question correctly then your main ambition is to dynamically change the url for the services based on a user defined variable.
This is very easy to accomplish and even easier to accomplish if you are using parsley / spicelib.
a few points
dont change the code in the super file, this will get overwritten whenever the service gets refreshed. change everything in its generated sub-Class.
Shared Objects are very good for small quantities of data but should never be used for massive datasets i.e storing a big arraycollection.
Anyway here is how i achieve this.
In the SubClass you can change the constructor function.
Here is how i change my urls based on a config variable but you can just as easily use a SharedObject instead.
public function SubClassConstructor(){
if(CONFIG::DOMAIN_IDENT == "development" || CONFIG::DOMAIN_IDENT == "dev" || CONFIG::DOMAIN_IDENT == "d"){
_serviceControl.endpoint = "http://yoururl1";
}
else if(CONFIG::DOMAIN_IDENT == "production" || CONFIG::DOMAIN_IDENT == "prod" || CONFIG::DOMAIN_IDENT == "p"){
_serviceControl.endpoint = "http://yoururl2";
}
}
Of course this isn't exactly what your looking for but its a working solution, of course you can use Bindings to a Global ApplicationModel or direct reference to the SharedObject i guess you already know how to use the SharedObject.
Ask if you need any further help or guidance.
As cghrmauritius' solution didn't quite work for me, I am posting up the final solution that did work in my situation.
public function subConstructor()
{
super();
_serviceControl.baseURL = "http://url1";
}
Obviously for my final solution I need to implement the shareobject as well but overriding the url was my main priority.