Saturday, 27 June 2015

CFML: I did not realise one cannot nest threads in CFML

G'day:
This is peer-group pressure at work. On IRC, Sean mentioned that in CFML (ColdFusion, Railo, Lucee... I have to admit I didn't think to look at OpenBD), one cannot nest thread calls. I was really surprised by this for a coupla reason:
  1. I was sure I would have - at some point - tried to do this. Even by accident.
  2. I couldn't see a good reason why.
Not that I doubted Sean, but he sugggested I did some investigation and write it up. I'm en route to Galway right now (ie: as I type I'm flying over Ireland), and I've had enough time to finish my previous article ("PHP: getting PHP 5 and PHP 7 running side by side on the same machine (a better way)"), and write the code for this article. So here goes.



First a baseline:

// baseline.cfm

writeLog(file="baseline01", text="Top of baseline.cfm ");
thread name="t1" action="run" {
    sleep(1000);
    writeLog(file="baseline01", text="Bottom of t1");
}
writeLog(file="baseline01", text="Bottom of baseline.cfm");

No nesting here, just a single additional thread fired off. This thread loiters for a second, then logs a log entry. This'll demonstrate that the code in the thread{} block is run asynchronously. This runs fine. This is the logged info:


"Information","http-bio-8511-exec-4","06/26/15","20:14:16",,"Top of baseline.cfm "
"Information","http-bio-8511-exec-4","06/26/15","20:14:16",,"Bottom of baseline.cfm"
"Information","cfthread-1","06/26/15","20:14:17",,"Bottom of t1"


See how the mainline thread (http-bio-8511-exec-4) finishes before the T1 thread (cfthread-1).

OK, lovely: everything as expected. So now for an attempt to nest stuff. Here's the most simple code to do so:

// nested.cfm

writeLog(file="nested01", text="Top of nested.cfm ");
thread name="t1" action="run" {
    sleep(1000);
    thread name="t2" action="run" {
        sleep(1000);
        writeLog(file="nested01", text="Bottom of t2");
    }
    writeLog(file="nested01", text="Bottom of t1");
}
writeLog(file="nested01", text="Bottom of nested.cfm");

And this yields:


"Information","http-bio-8511-exec-5","06/27/15","17:16:24",,"Top of nested.cfm "
"Information","http-bio-8511-exec-5","06/27/15","17:16:24",,"Bottom of nested.cfm"


So the second thread never ran. Looking in the application log we see why:

"Error","cfthread-0","06/27/15","17:16:25",,"T1: Thread T2 cannot be created. Child threads are not supported."

Hmmm, OK, well that bears out what Sean said.

I ran the same code on Lucee 4.5, and the results were similar.

It was a long-shot, but I wondered if it was something one could work around by abstracting the thread code into different files. I tried two different versions:
  1. using an include (via nestedViaInclude.cfm and nestedViaInclude.inc.cfm);
  2. using a method within a CFC (via nestedViaComponent.cfm, and NestedViaComponent.cfc).
There's no point regurgitating the code and the outcome here as it was exactly the same as above. So it cannae be done.

Ryan Guill had a fossick around in the Lucee source code, and found this:

/lucee-java/lucee-core/src/lucee/runtime/tag/ThreadTag.java

if(((PageContextImpl)pc).getParentPageContext()!=null)
    throw new ApplicationException("could not create a thread within a child thread");

I can't help but think they could simply not do that, and the world would be a better place.

Nice lack of braces and hard-coded exception message there btw :-/ I know I should no better than to look at source code of open source projects, sorry.

I wonder why both ColdFusion and Lucee decided to apply this restriction to us. I think it is as Sean postulated:
It was done (in ACF originally) to prevent poor ol' CFML devs from creating runaway threads and tanking their servers b/c concurrency is too hard for their widdle brains...
If it was that as opposed to some real-world limitation, Adobe can piss right off. Supercilious fucks. It does boggle the mind that Railo (I presume this code dates from Railo's time) followed suit.

I'm gonna raise tickets to get this restriction removed. ColdFusion: 4013671; Lucee: LDEV-410.

Cheers Sean and Ryan for giving me a topic today (it's now Saturday and I'm in the pub... I got the code done on the flight last night, but not the narrative).

Back to PHP next. Righto.

--
Adam