Ask Ben: Running ColdFusion Asynchronously - Caveman Style

Posted November 30, 2007 at 2:45 PM by Ben Nadel

Tags: ColdFusion, Ask Ben

Looking to run a CFM template asynchronously - aka: run it in the background. Gotchas:

* Must work under MX 6.1
* I can't use an event gateway
* Can't use CFSCHEDULE (unless you know of a way to post data to the URL)

Any ideas?

This reminds me of that old Polly-O String Cheese commercial where the guy walks into the pizza parlor and says something like, "Give me a pizza, hold the tomato sauce, hold the crust". What we are trying to do here is run an asynchronous task without all the fixins that make ColdFusion good at this.

Aside from the fact that I am not sure what bullet point #3 means, the only way I can think of doing this is to create a ColdFusion page that calls itself recursively using the CFHttp tag. This has all kinds of pitfalls which make my stomach feel uneasy, but in this sample code I am trying to put in some effect minimizers that stop this idea from totally crashing your machine.

  • <!--- Set file path. --->
  • <cfset strPath = ExpandPath( "./log.txt" ) />
  •  
  • <!--- Set safety file path (used at bottom). --->
  • <cfset strSafetyPath = ExpandPath( "./run.txt" ) />
  •  
  •  
  •  
  • <!---
  • Append the file hit. This is where you would normally
  • do your processing, but for our testing purposes, we
  • are just going to log the hit to a file.
  • --->
  • <cffile
  • action="append"
  • file="#strPath#"
  • output="#TimeFormat( Now(), 'HH:mm:ss.L' )#"
  • addnewline="true"
  • />
  •  
  •  
  •  
  • <!---
  • Sleep the thread for a little bit to give the
  • server a break before this starts to demand
  • resources once again.
  • --->
  • <cfset objThread = CreateObject(
  • "java",
  • "java.lang.Thread"
  • ).CurrentThread()
  • />
  •  
  • <!--- Sleep for 2 seconds. --->
  • <cfset objThread.Sleep(
  • JavaCast( "long", (2 * 1000) )
  • ) />
  •  
  •  
  • <!---
  • Before we call the page again, let's put in a
  • check to make sure that we don't run FOREVER. We
  • will only re-call the script if this file exists.
  • --->
  • <cfif FileExists( strSafetyPath )>
  •  
  • <!---
  • Since this file exists, re-run the page using
  • CFHttp with no wait time (or minimal wait time).
  • If you ever want to kill this file, just delete
  • that file.
  • --->
  • <cfhttp
  • url="http://#CGI.server_name##CGI.script_name#"
  • method="get"
  • timeout="1"
  • />
  •  
  • <p>
  • Your page has been re-launched in the background.
  • If you want to kill this process, simply delete
  • this file:
  • </p>
  •  
  • <cfelse>
  •  
  • <p>
  • This file cannot re-run until this file exists:
  • </p>
  •  
  • </cfif>
  •  
  • <!--- Ouptut safety file. --->
  • <p>
  • <cfset WriteOutput( strSafetyPath ) />
  • </p>

First, the help minimize some of the load on the ColdFusion server, I am asking the thread to sleep for 2 seconds before it re-launches itself using CFHttp. The second safety method is that this page will ONLY re-launch itself if the "run.txt" file exists. This file does nothing but server as a boolean flag; this is there so that you can delete or rename the file (run.txt) if you want the original script to stop running. This way, you could reasonably write another page that would conditionally rename the run.txt file based on URL params such that you could create a way to turn this script off using another script.

The caveat here is that you have to launch the first task manually. Once it gets going, though, it takes care of running itself.

Running this script, our log.txt text file ends up looking like this:

14:20:39.619
14:20:41.619
14:20:43.635
14:20:45.635
14:20:47.635
14:20:49.650
14:20:51.650
14:20:53.666
14:20:55.697
14:20:57.697
14:20:59.713
14:21:01.712
14:21:03.728
14:21:05.728
14:21:07.759

This whole thing makes me feel really uneasy. I am putting this out there because it was asked of me, but I really don't like it :) What might be a better methodology is to just build a simple HTML page that makes an AJAX call to the page every X number of minutes. The caveat there is that you need to keep that browser running, but at least it feels much safer to me.


You Might Also Be Interested In:



Reader Comments

Nov 30, 2007 at 4:10 PM // reply »
3 Comments

regarding bullet point #3:

You cant post variables directly from a scheduled task. But your scheduled task could call a cfm page that itself does a cfhttp call. In that cfhttp call, you post as many vars as you want.


Nov 30, 2007 at 4:25 PM // reply »
11,314 Comments

@Tim,

You're talking about a "POST" method right? In the user's question I was thrown by the statement "post data to the url". To me, this just sounds like query strings, which should be doable via a scheduled task (I am pretty sure). So maybe that is what they meant - posting to a URL as in (POST vs. GET).


Nov 30, 2007 at 5:06 PM // reply »
25 Comments

Don't forget about using cfheader and status code 204! If thats the first thing that gets processed in the target 'async' template, the calling page will move right along after receiving a response and the target template will continue to process in the background.


Nov 30, 2007 at 6:07 PM // reply »
37 Comments

AsyncHTTP!

http://www.compoundtheory.com/?action=displayPost&ID=137

I don't have tons of experience with it, but have verified it works in CF 6.1.


Nov 30, 2007 at 6:12 PM // reply »
11,314 Comments

@JAlpino,

That is very interesting. I will do some experimenting with the 20X status codes. Thanks for pointing that out.

@Aaron,

Mark's AsyncHTTP is very cool; it is one of the first things I found a while back when looking for that kind of functionality. Cool that it works CFMX6.1. Of course, this is basically doing the same thing as the CFHttp (I think) in terms of thread creation. The main difference is that there is no "Timeout" hack being used or required.


Nov 30, 2007 at 8:49 PM // reply »
24 Comments

Depending on what it's being used for you could also use a hearbeat type plugin with jQuery.

Alternately, you could refresh the page to itself with a meta refresh. Low-tech and utterly simple.


Dec 1, 2007 at 9:55 AM // reply »
6 Comments

Before CFThread came along I used a cfm page to do cfexecutes that would use wget at the command line to call the cfm pages to run asyncly.

-Randy


Dec 1, 2007 at 2:07 PM // reply »
11,314 Comments

All I can say is, thankfully CFThread came along and made our lives easier (and safer).


Dec 2, 2007 at 4:33 PM // reply »
132 Comments

One big problem with this that I can see is that it uses up one of those concurrent requests in the pool. So if you have the server set to only allow 6 concurrent requests, after doing this, you're only allowing 4 (on average since you'd spawn and wait with two requests while this thing was running).


Dec 2, 2007 at 6:10 PM // reply »
11,314 Comments

@Elliott,

Most definitely. This is certainly not something I would recommend. But, it was the only server-side way I could think of making this work with such limitations.


Dec 18, 2007 at 3:38 AM // reply »
1 Comments

This solution is awesome!

We were using the solution with manually creating schedule task which would run in 5 seconds and perform bunch of code once and then deleted itself.
We had to sync some data from out app to some other app that resided on different server and had some shitty db. Update call to their app was taking from 10 - 20 seconds. WAY TOO MUCH for us.

So we called the sync code in the background and continue to work with our app like everything was OK. We build log mechanism to control any failed syncs.

Anyway, cfhttp is way cleaner solution than cfschedule! BRAVO!

The simplest solution is probably the best one.


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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Jun 19, 2013 at 10:41 PM
Referencing ColdFusion Query Columns In A Loop Using Both Array And Dot Notation
Burdock-roots Are you going fat day by day? You need to be good for your family and make some money too. So we bring for you a best product that helps you to be more energetic every day. You will b ... read »
Jun 19, 2013 at 9:52 PM
Working With Inherited Collections In AngularJS
I recognize the applicability of your solution, and how easy it makes to share data across multiple views or even "submodules" of rather simple application. But it seems to me that it creat ... read »
Jun 19, 2013 at 9:38 PM
Directive Link, $observe, And $watch Functions Execute Inside An AngularJS Context
@Alesei, Glad you like it. Even after working with AngularJS for months, I still get a bunch of unexpected, "$digest is already in progress". So hard to debug sometimes! ... read »
Jun 19, 2013 at 9:36 PM
Working With Inherited Collections In AngularJS
@Mike, The relationship of $scope values is definitely an interesting thing! But it's not simple - it really forces you to understand prototypal inheritance, which is not at all a simple topic! Gla ... read »
Jun 19, 2013 at 9:35 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
@Joe, Oh, super interesting! I had only thought to url-encode the signature; but I think that's because the S3 docs actually have a special NOTE telling you to do so. It would have never occurred t ... read »
Jun 19, 2013 at 9:32 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
@Richard, Glad you like! Hopefully I'll have some more interesting stuff coming. This morning, I blogged a bit more about generating the pre-signed, query string authenticated URLs; but, then deeme ... read »
Jun 19, 2013 at 9:31 PM
Filter vs. ngHide With ngRepeat In AngularJS
@Mike, Honestly, in the majority of cases, I would say there isn't going to be a difference. Both approaches have trade-offs. If you use the filter, then you have fewer DOM elements and fewer $scop ... read »
Jun 19, 2013 at 2:01 PM
Experimenting With The Amazon Simple Storage Service (S3) API Using ColdFusion
I have coincidentally been beating my head against the S3 API for the last week or so. One big "gotcha" I had to work around was file names and paths containing spaces. Remember to URL Enco ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools