3

How do I do Asynchronous HTTP requests using CFHTTP tag?

I am looping over a Query result and send some data to a URL via HTTP post. There are lots of records in the query so cfhttp takes lots of time.

Is it possible to send asynchronous HTTP request in ColdFusion? Somebody suggested to me that I can create a thread and call cfhttp inside that. Is there any other way than cfthread?

Peter Boughton
  • 110,170
  • 32
  • 120
  • 176
Subbu
  • 3,299
  • 5
  • 24
  • 36
  • 5
    Why do you want a way other than with cfthread? – Peter Boughton Jan 25 '13 at 19:46
  • Do you need to wait until each cfhttp call is complete? or do you only care that they are all sent. – Kevin B Jan 25 '13 at 20:47
  • 1
    Have you tried ``? – Henry Jan 25 '13 at 23:59
  • I want to wait all the http calls are complete or not ? – Subbu Jan 26 '13 at 17:52
  • peter because i am using standard edition of CF and there is soem limitation to the thread in that version. – Subbu Jan 26 '13 at 18:20
  • There is a limitation of 2 concurrent thread executions in CF standard, but I think others will be queued, so you could still halve the time. Or you could split the work between 2 threads and execute them concurrently. You hay be able to write a custom Java class to do the threading, which may work around the limits, but I'm not sure whether that would work or not. The best approach if possible would be to modify the receiving web service to accept more than one record at a time, but I understand that may not be possible – barnyr Jan 28 '13 at 09:58

1 Answers1

1

As @peter-boughton suggested, use threads.

In CF 9.0.1 there is a bug with http inside a thread.

So, here's a quick prototype I did:

// cf_sucks_workaround.cfc
component extends="com.adobe.coldfusion.base" {
  public function cacheScriptObjects() {

    local.tags = ["CFFTP", "CFHTTP", "CFMAIL", "CFPDF", "CFQUERY",
      "CFPOP", "CFIMAP", "CFFEED", "CFLDAP"];

    for(local.tag in local.tags) {
      getSupportedTagAttributes(local.tag);
    }
  }
}
// async_http.cfm
<cfscript>
lg('start');
main();
lg('done');

void function main() {
    CreateObject('component', 'cf_sucks_workaround').cacheScriptObjects();
    startThreads();
}

void function lg(required string txt) {
    WriteLog(file = 'threads', text = "t#threadNum()# #arguments.txt#");
}

void function sendRequest() {
    var httpService = new http(timeout = "3", url = "https://www.google.com");
    lg('send http req.');
    var httpResult = httpService.send().getPrefix();
    lg(httpResult.StatusCode);
}

void function startThreads() {
    for (local.i = 1; i LTE 3; i++) {
        thread action="run" name="thread_#i#" appname="derp" i="#i#" {
            lg("start");
            sendRequest();
            lg("end");
        }
    }
}

numeric function threadNum() {
    return (IsDefined('attributes') AND StructKeyExists(attributes, 'i')) ? attributes.i : 0;
}

</cfscript>

Produces log output:

t0 start
t0 done
t1 start
t2 start
t3 start
t3 send http req.
t1 send http req.
t2 send http req.
t3 200 OK
t3 end
t1 200 OK
t1 end
t2 200 OK
t2 end
Jared Beck
  • 16,796
  • 9
  • 72
  • 97