Ask Ben: Limiting The Amount Of Time A Block Of Code Can Run

Posted April 2, 2007 at 8:10 AM by Ben Nadel

Tags: ColdFusion, Ask Ben

I have this application that uses a black-boxed piece of functionality. 98% of the time, this black-boxed functionality runs very fast as expected. Sometimes though, for reasons I cannot yet debug, this function takes so long that the page times out. Is there a way to make sure that just this block of code only executes for X number of seconds?

NOTE: Please disregard the solution below! Christoph Schmitz pointed out that this is a serious misunderstanding of how CFLock timeout works... I thought it was how long it could RUN... it is how long it will WAIT. Sorry for misleading anyone. I thought I was helping other people, but it turns out, this time, I get to learn something :)

Please see a better answer here: http://www.bennadel.com/index.cfm?dax=blog:618.view

For starters, we cannot force a piece of code to execute faster than it is going to on its own. If we could do that, I would make sure all my pages executed in 16ms. What we can do, though, is "misuse" the CFLock tag to make sure that your piece of code is only allowed to execute for X number of seconds before it throws an error. We can leverage the TimeOut attribute of the CFLock tag to allow the code a maximum amount of time in which it can run. If the CFLock times out and throws an error, we can then catch it and try to recover from the too-long-running task:

  • <!--- Try to execute the following block of code. --->
  • <cftry>
  •  
  • <!---
  • By putting a named lock on this block of code using
  • a CreateUUID() value, we can make sure it never
  • becomes single-threaded as no two CreateUUID()s are
  • the same. Furthermore, we can limit the amount of
  • time this code ran run by using the TIMEOUT attribute
  • of the CFLock tag.
  • --->
  • <cflock
  • name="#CreateUUID()#"
  • type="READONLY"
  • timeout="5"
  • throwontimeout="true">
  •  
  • <!---
  • This is our black-boxed piece of code. Not
  • sure how it works, but we know that 2% of the
  • time it runs way longer than it should and
  • crashes the page.
  • --->
  • <p>
  • This will only be allowed to execute for
  • a maximum of 5 seconds.
  • </p>
  •  
  • </cflock>
  •  
  •  
  • <!---
  • Catch an errors that get thrown from our
  • CFLock (if it times out).
  • --->
  • <cfcatch>
  •  
  • <!---
  • Our black-boxed piece of code has run too
  • long. Use this opprotunity to set default
  • values so that you might be able to recover
  • from this timeout.
  • --->
  •  
  • </cfcatch>
  •  
  • </cftry>

There are a few things to notice about the CFLock tag:

  1. We are using a named lock, not a scope lock. By using a named lock in conjunction with a CreateUUID() call, we can ensure that this block of code never becomes single threaded. This is good because I assume this page is not single threaded to begin with (so let's not force it to become so).
  2. We are using a timeout of 5 seconds. This gives the black-boxed code a maximum of 5 seconds to run. You can, of course, adjust this to be what you think it should be; however, this value should be smaller than the request time out of the page itself (otherwise, the page may crash anyway).
  3. We are having the CFLock tag throw an error if the time out is exceeded. This is the default value for the CFLock tag, but I put it in to drive the point home. This is key because the whole thing is wrapped in a CFTry / CFCatch block - the thrown error will give us a chance to recover from the long-running code. After all, the whole point of this is to NOT have the page crap out.

I hope this works for you. I would not exactly recommend this technique, though, as locking does come with processing overhead and I am not sure how this page is being used (high traffic?). Furthermore, I believe I read somewhere that repeated calls to CreateUUID() actually start to slow down your machine, but I cannot state that as fact, just hearsay.




Reader Comments

Apr 2, 2007 at 9:37 AM // reply »
26 Comments

Ben,

no offense man, but, you got cflock wrong somehow...

The timeout attribute of cflock specifies the time a request will wait until it aquires a lock, it does NOT specify the time a request within the lock may run. You can have a cflock-timeout of 1 second and still have the request run 100s of seconds.

So if you want the cflock to throw an exception, you need to make the lock exclusive and make the lock name static (make the code block single threaded) and then start a second request. Then this second request will timeout after 5 seconds.

IMHO the easiest way to timeout a request is the <cfsetting requesttimeout="x" /> tag.

Chris


Apr 2, 2007 at 9:41 AM // reply »
10,640 Comments

@Chris,

Oh man... you are totally right! Thanks for clearing that up for me. That is a huge misunderstanding in my mind. I knew it felt very wrong to use CFLock in this fashion - another reason now, it simply doesn't work that way.

Thanks for showing me the light :)


Apr 2, 2007 at 10:08 AM // reply »
10,640 Comments

@Christoph,

Does this look any better:

http://www.bennadel.com/index.cfm?dax=blog:618.view


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »