What Happens When A ColdFusion CFLock Timeout Is Exceeded Without Error?

Posted February 8, 2010 at 9:25 AM

Tags: ColdFusion

Last week, when I was working on my jQuery Photo Tagger plugin (for Flickr-style photo annotation), I was using CFLock to create thread-safe cache updates in the ColdFusion aspect of the code. As I was doing that, it occurred to me - I wasn't 100% sure what would happen if the timeout (indicated by the CFLock tag) was exceeded and no error was thrown? In the CFLock tag, you can use the ThrowOnTimeout attribute to determine the action taken by the thread if the a lock cannot be successfully obtained in the allotted time; but, what would that action actually be? Would the paused thread simply enter the CFLock tag body? Or, would it skip it?

 
 
 
 
 
 
 
 
 
 

I decided to get to the bottom of this by creating two tags that would compete for the same named lock. One thread pauses before the CFLock; one thread pauses whilst inside the CFLock. In this way, they get to it at different times and compete head-to-head for ultimate victory!. Here is the first page (a.cfm) which is the one that will have to wait for the CFLock:

a.cfm

 Launch code in new window » Download code as text file »

  • A: Before the CFLock tag.<br />
  •  
  •  
  • <!---
  • Pause this thread to make sure the other thread gets
  • to the CFLock first.
  • --->
  • <cfthread
  • action="sleep"
  • duration="750"
  • />
  •  
  • <!---
  • Get an exclusive lock (this named lock is shared with
  • the other thread). Notice that we are asking the page
  • NOT to throw an error if the lock cannot be made within
  • the given timeout.
  • --->
  • <cflock
  • name="cflockTimeoutTest"
  • type="exclusive"
  • timeout="1"
  • throwontimeout="false">
  •  
  • A: Inside the CFLock tag.<br />
  •  
  • </cflock>
  •  
  •  
  • A: After the CFLock tag.

Notice that the CFLock tag specifies that no error should be thrown if the lock cannot be gotten. The second page (b.cfm) gets to the CFLock tag first and then pauses, once inside, for a time that is greater than A's specified timeout:

b.cfm

 Launch code in new window » Download code as text file »

  • B: Before the CFLock tag.<br />
  •  
  •  
  • <!---
  • Get an exclusive lock (this named lock is shared with
  • the other thread).
  • --->
  • <cflock
  • name="cflockTimeoutTest"
  • type="exclusive"
  • timeout="1">
  •  
  • B: Inside the CFLock tag.<br />
  •  
  • <!---
  • Once inside the tag, let's sleep the thread so that
  • the lock will be held for a while (preventing the other
  • page from entering within the given selected timeout).
  • --->
  • <cfthread
  • action="sleep"
  • duration="#(3 * 1000)#"
  • />
  •  
  • </cflock>
  •  
  •  
  • B: After the CFLock tag.

Notice that this page pauses its lock for 3 seconds, which is greater than the one second timeout specified in page A.

I then put these two pages head-to-head in a Frameset (I won't bother showing the code for that) to see what would happen. When I ran the two pages at the same time, I got the following output from A:

A: Before the CFLock tag.
A: After the CFLock tag.

... and the following output from B:

B: Before the CFLock tag.
B: Inside the CFLock tag.
B: After the CFLock tag.

As you can see, when page A failed to get a lock in the specified timeout, it simply skipped over the CFLock tag altogether. This is good; this is the outcome that I was hoping for (and one that I have coded against) and it's nice to see that it is what actually happens. At least I don't have to go back and fix my code.

So, why would one not want to throw an error if a lock was not obtained? I think this is definitely a rare case, but one that I have used a few times. Typically, I will use this if I am inserting / mutating large amounts of database records containing very non-critical information. In such a case, I might not care if periods of intense performance fail to insert a few rows here and there.

Another place where I actually use this a lot is within a scheduled task. If I have a scheduled task that might take a while to run, I will typically wrap the entire task in a named CFLock tag with a timeout of one second. This way, if the scheduled task tries to execute while the previous instance is still running, the scheduled task will simply skip over itself.

After you've written a bunch of code under a given assumption, it's always a bit scary to realize that you've never tested to confirm the behavior you were expecting. When it comes to CFLock, it's nice to see that when a thread cannot obtain a lock in the given timeout, it skips over the tag altogether.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Print Page





Reader Comments

Feb 18, 2010 at 11:44 PM // reply »
78 Comments

I'd never thought to use a named lock to guarantee that frequently running scheduled tasks wait for themselves! Genius.

I can't believe that the minimum timeout you can use is 1 second. That's like 10 minutes in Internet years.


Feb 19, 2010 at 2:48 PM // reply »
7,572 Comments

@David,

Thanks my man - it's a method I've found very useful for long running tasks.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 22, 2010 at 3:08 AM
Ask Ben: Selecting XML Attributes Given Other XML Attributes
Thanks for the response. I finally discovered that I was getting this error because I had cfsetting enablecfoutputonly="yes" in Application.cfc, and was neither setting it to false elsewhere nor brac ... read »
Mar 21, 2010 at 8:57 PM
The Bourne Ultimatum Starring Matt Damon And Julia Stiles
late to the party, but my observation is this: rewatch carefully for the platonic nature of the relationship between nicki and jason. she never flirts with him. he never comes on to her. they alway ... read »
Mar 21, 2010 at 7:40 PM
Is Simulating User-Input Events With jQuery Ever A Good Idea?
A couple of things. One you embed the initial state of of more-info in the CSS. IMHO, that behavior should be in jQuery: moreInfo.hide(); It shows that the behavior your toggling and closing is mor ... read »
Mar 21, 2010 at 3:59 PM
Exploring ColdFusion Component Runtime Class Properties And Serialization
@Elliott, according to Ben's experiment, serializeJSON() doesn't access the private data by default - it doesn't even access the getHair() method - so trying to clone a Girl.cfc via serializeJSON/des ... read »
Mar 21, 2010 at 3:49 PM
Ask Ben: Javascript String Replace Method
I'm confused a bit by what you are asking, but if had this sentence: The color, red, is in the style statement; style: red;. and wanted to remove all or change all of the commas, colons, and semi-c ... read »
Mar 21, 2010 at 3:13 PM
Ask Ben: Javascript String Replace Method
I am trying to make a java program to count the number of times that these punctuation marks occur in a body of text: , : ; . ! - ' " ? / \ I am using this piece to ferret out the commas: numcommas ... read »
Mar 21, 2010 at 11:13 AM
A New Wrist Pain
@chiropractor suwanee, Spoken like someone trying to sell something. Other than for minor, temporary relief from some back pain, chiropractic treatment is nothing but placebo effect and quackery. ... read »
Mar 21, 2010 at 6:32 AM
ColdFusion CFPOP - My First Look
Apologies... The field name in the db for C. is "BounceCode" It stores the code / message which is returned in the email. Sorry for the confusion. ... read »