Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Michelle Kong and Aaron Grewell and Shawn Grigson and Jeremy Mount and Kevin Johnson and David Epler and Johnathan Hunt and Sara Dunnack and Jeremy Kicklighter
Ben Nadel at InVision In Real Life (IRL) 2018 (Hollywood, CA) with: Michelle Kong , Aaron Grewell , Shawn Grigson@shawngrig ) , Jeremy Mount , Kevin Johnson , David Epler , Johnathan Hunt@JHuntSecurity ) , Sara Dunnack@SunnE_D ) , and Jeremy Kicklighter

Time-Boxing A CFThread And Then Terminating It If It Takes Too Long To Complete In ColdFusion

By Ben Nadel on
Tags: ColdFusion

Every now and then, I have some processing that I need to perform in ColdFusion; but, I want to time-box the processing such that I can terminate it if it runs for too long. As of late, I've been using the CFThread tag to carry out this scenario. I'll spawn an asynchronous "worker" CFThread; then, block and wait a fixed-amount of time for the worker thread to complete. And, if it doesn't complete in the given time, I ask ColdFusion to terminate the worker thread.

I touched on the topic of terminating asynchronous CFThreads a few years ago. But, in that first post, there was no concept of time-boxing the thread - only terminating it. In this post, I'm going to use the "join" action with a "timeout" to block and wait before inspecting the asynchronous thread for its execution status.

When you provide a "timeout" to the CFThread "join" action:

  • <cfscript>
  •  
  • thread
  • name = "target-thread-id"
  • action = "join"
  • timeout = 3000
  • ;
  •  
  • </cfscript>

... it blocks the processing of the parent request until the target thread either completes; or, the timeout has been passed. And, if the timeout is passed, the parent request processing picks up and continues processing the request. Because of this behavior, we can use this "timeout" value to time-box the CFThread execution. And then, we can use the CFThread scope to inspect the state of the target thread.

To see this in action, let's spawn a CFThread that we know will take too long to join. Then, we'll look at the CFThread state and terminate it if its still running:

  • <cfscript>
  •  
  • workerThreadID = "my-worker-thread";
  •  
  • // Start a worker thread that is going to perform some processing that we want to
  • // time-box. And then, kill if it takes too long to run.
  • thread
  • name = workerThreadID
  • action = "run"
  • {
  •  
  • // Imagine "real processing" happening here.
  • sleep( 5000 );
  •  
  • }
  •  
  • // ------------------------------------------------------------------------------- //
  • // ------------------------------------------------------------------------------- //
  •  
  • // Now that the worker thread is off doing its thing, we want to give it a limited
  • // amount of time to complete its work and return. To do this, we're going to use the
  • // JOIN action with a TIMEOUT. The TIMEOUT will ask the parent page to stop and wait
  • // for the target thread to complete. And, if it doesn't complete in the allotted
  • // time, the parent thread will just PROCEED with the request processing.
  • thread
  • name = workerThreadID
  • action = "join"
  • timeout = 3000 // After 3-seconds, proceed with request.
  • ;
  •  
  • // At this point, the request processing is proceeding. Bet we don't know if this is
  • // because the worker thread completed; or, because the "join" action timed-out after
  • // 3-seconds. As such, we have to inspect the state of the worker thread.
  • workerThread = cfthread[ workerThreadID ];
  •  
  • // Check to see if the worker thread is still pending.
  • if (
  • ( workerThread.status == "NOT_STARTED" ) ||
  • ( workerThread.status == "RUNNING" )
  • ) {
  •  
  • // The worker thread has not completed in time; ask ColdFusion to terminate it!
  • thread
  • name = workerThreadID
  • action = "terminate"
  • ;
  •  
  • writeOutput( "Terminating worker thread - taking too long to complete." );
  •  
  • } else {
  •  
  • writeOutput( "Worker thread completed in time." );
  •  
  • }
  •  
  • </cfscript>

As you can see, we have a worker CFThread that will sleep for 5-seconds. But, our "join" action is going to time-box it to 3-seconds. Then, after the 3-seconds is completed, we check to see if the worker thread is still executing (which know it will be); and, ask ColdFusion to terminate it.

Now, when we run this code, we get the following ColdFusion output:

Terminating worker thread - taking too long to complete.

With this approach, if the worker thread completes before the timeout has passed, the status of the thread will be "COMPLETED" (or possibly "TERMINATED") at the time we go to inspect it. As such, we'll skip the "terminate" request and just continue on with the parent page processing.

It's not often that I need to time-box the execution of a CFThread tag in ColdFusion. But, when I do, I have found this approach to be straightforward and reliable.



Looking For A New Job?

Ooops, there are no jobs. Post one now for only $29 and own this real estate!

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

Hi, Ben. Interesting stuff as always. I do have a concern for you and readers. I'm both this post and the other, you show doing a sleep.

Just beware that while such a sleep can be terminated, many common operations that could hang up a request (or thread) will NOT terminate on request like that. For instance, a long-running query, or cfhttp call, or file i/o, and the like.

Or at least I can confirm that as a request they can't, and we should confirm if somehow a thread termination would kill a thread doing them. I'm not at my computer to adequately test.

For those interested, I have more on the matter (regarding requests) in this old post of mine (which remains true today):

https://www.carehart.org/blog/client/index.cfm/2010/10/15/Lies_damned_lies_and_CF_timeouts

If you or any of us can get a chance to confirm things, it would be useful to add here.

Reply to this Comment

@Charlie,

Absolutely great point. I wish I could find the snippet of document -- and I may totally be making it up -- but I swear I just read somewhere that there is a note that terminate will ask the JVM to terminate the thread, but does promise that it will actually take place. I could swear I read that somewhere; but, it could have been a dream.

I should be able to test with a long running query (one that just does a SLEEP on the MySQL server). I'll get back to you.

Reply to this Comment

@Charlie,

That said, I do definitely remember when I was using Fusion Reactor (I miss those days), the request to terminate a given request didn't always work :D

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
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.