Showing posts with label StackOverflow. Show all posts
Showing posts with label StackOverflow. Show all posts

Sunday, 14 August 2022

JS: Server-sent events

G'day:

Yes, it's very odd for me to have something to say about JS stuff. I don't imagine there's anything new here for people that actually do JS development, but I don't, so this feature is new to me. Maybe it'll be new to some of my readers too.

I was looking at a question on Stack Overflow tagged with "ColdFusion": Server Side Events and Polling Database for new records with Lucee/Coldfusion. There was no answer, and I didn't know what the questioner was on about, so I decided to have a look.

Firstly, I RTFMed the JS words I didn't recognise:

The from ferreting around in the docs further, I found a PHP example of the server-side part: MDN › References › Web APIs › Server-sent events › Using server-sent events

From that lot it was easy to knock-together a CFML example.

<!-- test.html -->

<div id="result"></div>

<script>
var source = new EventSource('testInLoop.cfm');

source.addEventListener('message', function(e){
    document.body.innerHTML += `${e.data}<br>`
});
</script>
// testInLoop.cfm

header name="Content-Type" value="text/event-stream";

requestStartedAt = now()
for (i=1; i <= 10; i++) {
    data = {
        "uuid" = createUuid(),
        "now" = now().timeFormat("HH:mm:ss"),
        "requestStartedAt" = requestStartedAt.timeFormat("HH:mm:ss")
    }
    writeOutput("event: message" & chr(10))
    writeOutput('data: #serializeJson(data)#' & chr(10) & chr(10))
    flush;
    sleep(1000)
}
writeOutput("event: message" & chr(10))
writeOutput('data: #serializeJson({"complete": true})#' & chr(10) & chr(10))
flush;

Miraculaously, this works:

{"uuid":"4E1A4D17-6E4A-410B-B9C26B420A0DD5B4","now":"11:15:40","requestStartedAt":"11:15:40"}
{"uuid":"65C3F605-8823-4BF5-B32550FEABD0CECC","now":"11:15:41","requestStartedAt":"11:15:40"}
{"uuid":"D22E86D0-872F-4E5F-A89B29F44314BE05","now":"11:15:42","requestStartedAt":"11:15:40"}
{"uuid":"C4B6C1A6-0EF6-4CFD-AC9D4791F14A74AA","now":"11:15:43","requestStartedAt":"11:15:40"}
{"uuid":"FE0DB9CA-3535-416C-B63066EC4913E87D","now":"11:15:44","requestStartedAt":"11:15:40"}
{"uuid":"3E4E2DED-5B57-40AB-B8F5886DC7983053","now":"11:15:45","requestStartedAt":"11:15:40"}
{"uuid":"19611965-34D0-4ED4-9B9260B7EE3D8941","now":"11:15:46","requestStartedAt":"11:15:40"}
{"uuid":"81C7066F-55AD-47F1-BBBEC6EDAAA7A7C4","now":"11:15:47","requestStartedAt":"11:15:40"}
{"uuid":"2477899D-50EB-4CB0-AAF8E681DF168087","now":"11:15:48","requestStartedAt":"11:15:40"}
{"uuid":"7ABF54BD-1618-458D-A6BBF5D07812564D","now":"11:15:49","requestStartedAt":"11:15:40"}
{"complete":true}
{"uuid":"44AA5416-8EA9-451B-95C60E2BC1F4CEF8","now":"11:15:53","requestStartedAt":"11:15:53"}
{"uuid":"8829A145-93D5-4175-9305414B32CBE83E","now":"11:15:54","requestStartedAt":"11:15:53"}
{"uuid":"15F96712-263C-4798-ABCDBDC0C0AA68F7","now":"11:15:55","requestStartedAt":"11:15:53"}
{"uuid":"AF3A1831-8817-400E-B1292B4FCBD8BDDC","now":"11:15:56","requestStartedAt":"11:15:53"}
{"uuid":"C3D9D100-C8A9-4A92-87F6E62138DB5C6F","now":"11:15:57","requestStartedAt":"11:15:53"}
{"uuid":"1E60C5D6-E16A-429C-804D32B278272872","now":"11:15:58","requestStartedAt":"11:15:53"}
{"uuid":"DDB2DA3C-D064-4F6E-80227E337B41D657","now":"11:15:59","requestStartedAt":"11:15:53"}
{"uuid":"E7034B05-7912-4971-9ECD76E07403AD49","now":"11:16:00","requestStartedAt":"11:15:53"}
{"uuid":"D0D17279-6531-42B9-AB21FFB76DA5D939","now":"11:16:01","requestStartedAt":"11:15:53"}
{"uuid":"D804394F-DCB7-4FE3-BB6AAD86A4865D7D","now":"11:16:02","requestStartedAt":"11:15:53"}
{"complete":true}
{"uuid":"C25CF442-18FB-4BDD-8B55811E6DDCCD13","now":"11:16:06","requestStartedAt":"11:16:06"}

One thing to note is that once the server-side request completes, the browser (Chrome for me) re-polls the server after seemingly 4sec. I could not find anything in the docs about this (or how to set the interval). I've just tested in Edge and Firefox too, and their behaviour is the same as Chrome, except Firefox's interval seemed to be 6sec not 4sec.

That's all I have to say on this. Pleased to know about it, and pleased to be able to answer that Stack Overflow question now.

Righto.

--
Adam

Thursday, 3 November 2016

PHP: different ways of defining one-off objects

G'day:
This one came from a Stack Overflow question I watched be raised, commented-on and summarily closed again because there are rules to follow, and by golly the community moderators on S/O looove following rules.

Anyway, the question got asked, but never answered.

'ere 'tis:

In PHP 7, what's the use of stdClass with the availability of anonymous classes?


As of PHP 7 we have access to anonymous classes. This means we could ditch stdClass when we need generic object as a return value... But which one would be cleaner?
  • What other differences are between those two guys?
  • Is there any performance drawback on creating an anonymous class? i.e. as each one has a different "class name", is there any additional impact?
  • Do both work "the same way" from the developer point of view, or are they actually two different beasts in some cases?
<?php
$std_obj = new stdClass(); //get_class($std_obj) == 'stdClass'
$anonymous = new class {}; //get_class($std_obj) == 'class@anonymous\0file.php0x758958a3s'

Good question. Well the bit about performance ain't, cos at this stage of one's exploration into these things - asking initial questions - one clearly doesn't have a performance issue to solve, so just don't worry about it.

OK, so I like messing around with this sort of thing, and I still need to learn a lot about PHP so I decided to refresh my memory of the various approaches here.

Firstly, the "anonymous classes" thing is a new feature in PHP 7, and allows one to model objects via a literal expression, much like how one can define a function via an expression (making a closure) rather than a statement. Here's an example:

$object = new class('Kate', 'Sheppard') {

    private $firstName;
    private $lastName;
    
    public function __construct($firstName, $lastName){
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }
    
    public function getFullName(){
        return "{$this->firstName} {$this->lastName}";
    }
};

See how go new class, and then proceed to define the class right there in the following block. Note this doesn't create a class... person1 does not contain a class; it creates an object. As evidenced by my subsequent usage of it:

echo $person1->getFullName();

Output:

Kate Sheppard

TBH, I dunno about the merits of this. In PHP one can already declare classes in the same file as other code, and more than one class in the same file. I guess it's handy for when one needs to define a one-off modelled object within another function or something? I dunno.

The other version mentioned was via stdclass, but let's not go there yet.

Now bear in mind the OP was asking about creating empty objects. One can do that with an anonymous class by just not giving the class definition any body:

$empty = new class(){};

Dumping that out gives:

object(class@anonymous)#1 (0) {
}

And with stdclass:

$empty = new stdClass();

Dumping that out gives:

object(stdClass)#1 (0) {
}

Not much to it. But I dunno if the intent in PHP is to use stdClass directly. The docs just say:

Created by typecasting to object.

It doesn't say "instantiate one of these to create an empty object". And that's where it'd say it, if that was the intent.

What it does allude to is this:

$empty = (object) [];

Dumping that out gives:

object(stdClass)#1 (0) {
}

(so same as with stdClass). To me the intended usage of stdClass is just one of inference. An array cast to an object needs to be of some type, so there's stdClass to accommodate that.

Also: how often does one want an empty object, and that's it? At least with casting an array to an object one can give it some properties off the bat:

$person = (object) [
    'firstName' => 'Kate,
    'lastName' => 'Sheppard'
];

One can add properties to the object afterwards with a new stdClass(), but that seems clunky.

Thinking about it, using new stdClass() seems about as right a way to do things as using array() to declare an array, as opposed to using a literal []. Bleah. Just use the literal.

But this all got me thinking though. Empty objects be damned. How can I implement the same as that anonymous class using these other syntaxes.

I managed to write some really crap code implementing analogues using stdclass and an object literal.

First the object literal, as it's not too awful:

$person2 = (object) [
    'firstName' => null,
    'lastName' => null,
    '__construct' => function ($firstName, $lastName) use (&$person2) {
        $person2->firstName = $firstName;
        $person2->lastName = $lastName;
    },
    'getFullName' => function () use (&$person2) {
        return "{$person2->firstName} {$person2->lastName}";
    }
];

It's not sooooo bad. Until one ones to try to use it. Check this out:

$person2->__construct('Emmeline', 'Pankhurst');
echo $person2->getFullName() . PHP_EOL;

This just gives:

PHP Fatal error:  Uncaught Error: Call to undefined method stdClass::__construct() in literalVsObjectCast.php:37
Stack trace:
#0 {main}
  thrown in literalVsObjectCast.php on line 37

Yikes. This turns out to be some weirdo order of operation things, and I can't quite remember what the story is, but it's down to how and what the function call is bound to the function, and the -> operator taking precedence over the () operator. Or something.

It's easily enough solved:

($person2->__construct)('Emmeline', 'Pankhurst');
echo ($person2->getFullName)() . PHP_EOL;

See how I've used parentheses there so the method calls are on the reference to the object/method. This works:

Emmeline Pankhurst

But it's unorthodox code, so I'll be avoiding that. Oh yeah, also notice the weirdness I had to do with the reference with the closure there. Plus having to reference the object's properties by this "external" reference. Still: good to be able to do it though.

We can go from "unorthodox" to "shit" now. There's the equiv using stdclass:

$person3 = new stdclass();
$person3->firstName = null;
$person3->initial = null;
$person3->lastName = null;
$person3->__construct = function ($firstName, $initial, $lastName) use (&$person3) {
    $person3->firstName = $firstName;
    $person3->initial = $initial;
    $person3->lastName = $lastName;
};
$person3->getFullName = function () use (&$person3) {
    return "{$person3->firstName} {$person3->initial}  {$person3->lastName}";
};

And again to run it, we need to use those extra parentheses:

($person3->__construct)('Susan', 'B', 'Anthony');
echo ($person3->getFullName)() . PHP_EOL;


Susan B Anthony

It's all a bit grim for words: the literal version was a bit awkward, but this as all the awkwardness as well as a lot of clutter (and, yes, this version also supports a middle initial, but that's not really the bulk of the bloat).

Another thing with these latter two versions is that - until the class literal version - firstName and lastName are public. I guess it's no big thing for throwaway objects, but it seems a bit "leaky" to me.

One of these JavaScript tricks we learn when trying to fit the oval peg into the round hole that is "doing OO in JS", is the Module Pattern: using an IIFE to emulate an object with private data. PHP 7 also added IIFEs, it already has closure, so we can do this in PHP too:

$person4 = (function($firstName, $lastName){
    return (object)[
        'getFullName' => function() use ($firstName, $lastName){
            return "$firstName $lastName";
        }
    ];
})('Vida', 'Goldstein');


And running it:

echo ($person4->getFullName)() . PHP_EOL;

Output:

Vida Goldstein

Now I reckon that's the tidiest syntax of all! Even beating the anonymous class version. But one is still stuck with those extra parentheses on the function call though. Pity.

In conclusion, I reckon this:

  • if you want an empty object... use (object)[]. Don't use a mechanism - anonymous classes - specifically intended to derive fully modelled objects, just to create empty objects.
  • If you want a throw-away object with a few public properties in it it: still use (object) []. It's tidier and less typing.
  • If you need some methods in there as well... go for the anonymous class literal; its usage syntax is more orthodox than using the IIFE.
  • But do remember PHP7 has IIFEs! They come in handy for things other than emulating JS design patterns.
  • I don't reckon one ought to directly use stdClass. It's clunky, leads to bloated code, and the docs kinda position it as a necessary implementation, not something that one's supposed to actively use.
  • But... generally speaking use a proper named class. These anonymous classes are not a replacement for them; they're for throw-away objects. You'll seldom need those.
  • Don't start an exercise worrying about performance. Write good clean code, using TDD, and worry about performance if it comes up. And differences like this are never gonna be where to make savings anyhow.

Thoughts? Obviously I'm just a relative n00b at PHP so I might be missing some important thing that seasoned PHPers all "get" but I've not come across yet. Lemme know.

Righto.

--
Adam

Monday, 28 March 2016

Another example of premature optimisation

G'day:
I initially posted this to Stack Overflow, but with a mind to releasing it here too. It's worth repeating.

The original question was along these lines. Given two approaches to making two decisions, which is the most performant:

function f(){

    // other code redacted

    if (firstBooleanValue && secondBooleanValue){
        return true;
    }
    return false;
}

Or:
function f(){

    // other code redacted

    if (firstBooleanValue){
        if (secondBooleanValue){
            return true;
        }
    }
    return false;
}

Someone else answered with a loop-de-loop amplification test to demonstrate [something, I don't care which way it came out, and nor should you], but they did caveat it with "it doesn't matter".

My answer was as follows:

I know @tom starts his answer by saying "it doesn't matter", but this cannot be stressed enough, so I'm going to elaborate further in a separate answer.

@piotr-gajdowski: just don't worry about this sort of thing. If one needs to loop thousands of times to see a difference, this implies it's a case of micro-optimisation. The differences here will be lost in the background noise of any other consideration going on at the same time, for example:
  • what else the server is doing at the time;
  • network latency variation;
  • how busy external dependencies like DBs are at the time.
So... it simply doesn't matter.

Always go for the code that you find clearest, and - more importantly - that other people will find the clearest. This generally means the simplest.

For your specific situation, given you given us "fake" code, it's impossible even to say given your example what that might be:
  • how complex are the two conditions?
  • Are they really just single variables?
  • Do the variables have explanatory names?
  • If they conditions are actually boolean expressions rather than variables... consider putting them in well-named intermediary variables.

These are the things you should be worried about.

Write your code as clearly as possible (this doesn't not necessarily mean as tersely as possible, btw). If at some point you find you have performance issues, then (and only then) start looking for optimisations. But don't start looking for this sort of optimisation. Start looking for things that will make a difference.

I think the best thing you could do with your code example would be to submit the real world code to Code Review, and then we can help you come up with the clearest approach to coding it. That's the question you should be asking here.
If all we had to go on was the example provided, then it's difficult to say what the clearest approach would be here. The variable names are nonsense in the posted code, so one cannot infer much from them.

If say we are talking about two variables, and they're clearly named, this would be a clear option:

function canAttendMeeting(){

    // other code redacted

    return hasFreeTime && isInOffice;
}

If however there's no intermediary descriptive variables hasFreeTime and isInOffice, then don't do this:

function canAttendMeeting(){

    // other code redacted

    return (meetingStart > dayBegin & meetingStart < datEnd & withinFreePeriod(meetingStart, meetingEnd)) && (person.locationAtTime(meetingStart, meetingEnd) == "office");
}

Stick 'em in intermediary variables.

If the logic to derive the second boolean expression is somehow predicated on the first condition condition being true, and short circuiting won't work, then I'd consider taking an early exit over a nested if:

function f(){

    // other code redacted

    if (not firstBooleanValue){
        return false;
    }
    if (secondBooleanValue){
        return true;
    }
    return false;
}

All things being equal, I attempt to keep my code as close to the left margin as possible. If I have to scan for the end of a logic block, rather than just see it at the same time as the top of the logic block, I've probably got a chance to simplify the logic. I am always a bit wary of of having a negative expression in a decision statement, so if poss I'd try to reverse the name of an intermediary variable:

function canAttendMeeting(){

    // other code redacted

    if (doesNotHaveFreeTime) {
        return false;
    }

    // other code only possible if the person has free time
    
    return isInOffice;
}

And there will be other variations which are more or less viable given the circumstances. But generally the consideration is code clarity, not micro-optimising a situation not yet known to need it. And in that case, one needs to consider things a bit more clearly than how to order if statements.

Righto.

--
Adam

Friday, 20 November 2015

ColdFusion: help one of our community members with a PDF problem

G'day:
One of our community members, Prabha (I dunno the rest of their name), is having some problems with PDFs. They came to me for help, but I don't know the first thing about PDFs nor how to manipulate them with ColdFusion. And to be completely honest, I am completely content maintaining that ignorance. But I know a bunch of people out there do know how to do this stuff, so they might be able to help.

The question is this one, on StackOverflow: "When exporting PDF with CFChart images in ColdFusion It shows embedded font error". I can't actually make head or tail of it, but there seems to be two things:

They're getting this error:

"cannot extract the embedded font 'PCBOHZ + TimesNewRomanPS-BoldMT. some characters may not display or print correctly ( OR ) cannot extract TimesNewRomanPS-BoldMT"

And clearly they'd rather not.

Secondly there's something about images missing:

In the generated PDF the images are showing as red cross marks, while creating PDF, CFDOCUMENT makes HTTP URL calls to coldfusion server to get the images from the CF virtual folder CFIDE/CFSERVLET (because these images are saved in this folder by cfchart tags based on the charting settings in CF administrator) [...]
It's all greek to me.

Now these should be two different questions on StackOverflow, but... err... shrug.

If there are any ColdFusion/PDF experts out there, can you have a look-see and try to help? Cheers.

Righto.

--
Adam



Tuesday, 16 December 2014

F***ing StackOverflow. And new vs createObject() vs entityNew()

G'day:
I was typing this response on Stack Overflow, and just as I was finishing, the question was closed and I was unable to save it. What a bunch of pricks the rule-makers on StackOverflow are.

I'm not having my work wasted, so I'm publishing it here instead.

Obviously any thoughts or elaborations are welcomed.

Saturday, 22 November 2014

My answer to a question on Stack Overflow about DI

G'day:
I'm re-posting this here, hoping to get feedback from the DI doyens like Sean, Brad and Luis. Plus it's an easy article to post whilst I get together my article about Dave's Python code (from the quiz: "Something for the weekend? A wee code quiz (in CFML, PHP, anything really...)").

The question is here: "Dependency injection is only for testing?", and I'll reproduce it here (I'll ask the OP if this is OK, and remove/summarise if not):

Saturday, 1 November 2014

PHP & CFML: mapping and reducing

G'day:
I'm trying my hardest to answer PHP questions on StackOverflow these days, but the PHP community is so large and my PHP knowledge is so neophytic that I am never an early-enough bird to catch the worm for the easy questions. Plus a lot of the "PHP" questions are actually asking framework specific questions, and I have no idea about Laravel, Zend etc.

Still: I found an interesting question today with a pedestrian answer, so I decided to offer my own answer (to the actual question as asked). The answer would have been easy in CFML, but it was a bit of a ball-ache in PHP.

Wednesday, 13 August 2014

Even newbies can help solve community problems

G'day:
I was quite pleased yesterday when I got my first "accepted answer" for a Ruby-tagged question on Stack Overflow. I hasten to add that the question was one of converting CFML code to Ruby code, so I had a helping hand, plus it was simply a matter of seeing where the logic of the Ruby code didn't match that of the CFML. I think even someone not versed in Ruby at all could answer it. So I'm not claiming it as much of a personal achievement.

What is good about it is that it demonstrates that answering questions on Stack Overflow is not the sole purview of experts in a given field; even newbies and intermediate-levelled people can provide good input into other people's questions. Also, it's a great learning exercise. Stepping out of one's own comfort zones and into someone else's problem domain exposes us to technology and concepts we might not use every day. The code we use at work is very five-tagger (perhaps "ten-tagger" might be a better description; reading "Five-tagger? what n-tagger am I?"), and I never use CFML's UI tags, PDF tags, image-processing tags, spreadsheet tags, .net integration, etc. So when I see someone asking a question on those topics, it's a good excuse to roll my sleeves up and find out what the answer is. This helps both the petitioner as well as myself. Win. So imagine if you're a less experienced CFML developer (purely chronologically, I've been doing CFML for 14 years, so I have picked up a reasonable amount of knowledge along the way, so I don't think it's hubris to imply I'm "experienced"), there is even more scope to learn more new stuff.  Don't use CFCs? Check how people are using them in the real world. Don't use CFScript? There's a lot of CFScript code on show on Stack Overflow. Have never used a "closure" in your life? Here's your chance to see them in action.

Saturday, 12 July 2014

Oh dear. I am a big meany again

G'day:
This greeted me in my in box just now:

Adam,
We can do without some of the petty comments and downvotes and suggested closures from people such as yourself on Stackoverflow.
Thanks,
[person's name provided]

Tuesday, 17 June 2014

I'm not Ben Nadel (or Ray Camden)

G'day:
Just a quick note. Ben Nadel has a feature on his blog to "Ask Ben" via which the community can contact him directly for help. I think Ray might also have this on his blog too.

However I'm neither of those people, and I won't help people if they come directly to me via email with their coding problems.

Wednesday, 16 April 2014

Odd behaviour with struct keys with dots in their names

G'day:
I've been looking at this one due to an interesting question on Stack Overflow: "Confusion in dynamic variable access in ColdFusion". I could not immediately see what the problem was, and it's taken me a coupla hours to work out what's going on.

Monday, 21 October 2013

Best description of Stack Overflow "community" ever...

G'day
Someone just left this comment against an older blog article on a similar topic:
Stack Overflow is basically the Stanford Prison Experiment playing out on the internet.
Classic.

--
Adam

Wednesday, 21 August 2013

Cocks: or "the Stack Overflow community" as they perhaps prefer to be known

G'day:
F*** me Stack Overflow is populated by cocks. I was amidst answering someone's CFML question when an insecurity of self-appointed moderators (I have decided "insecurity" is an apt collective noun for these people) closed the question underneath me, so I could not post the answer.

Saturday, 4 May 2013

Code Review

G'day:
I became aware of Stack Exchange's Code Review website a few months back, but never really looked at it until today. I decided one way to get someone other than Bruce (no offence! ;-) to look at my PHP code would be to chuck it up there and see what happened. Well so far nothing has, but it's the weekend etc, so perhaps people have better things to do than review my code on the weekend. How this can be true I don't know, but the world is a funny place.

Anyway, they have a ColdFusion / CFML channel too, so it might be a place to chuck yer code up there to get reviewed.

Tuesday, 23 April 2013

CFML compilation into Java .class files

G'day:
Once again, Stack Overflow is my muse. Today a person called David Mulder is asking a question the answer to which relates to how CFML source code is processed into a Java .class file before the class file is then executed.

David's question was basically why this code doesn't behave how one might hope:

<!---test.cfm --->
<cfset msg = "G'day World">
<cfoutput>
<cfinclude template="incNoOutput.cfm">    
</cfoutput>
<cfinclude template="incWithOutput.cfm">

<!--- incNoOutput.cfm --->
#msg#<br>

<!--- incWithOutput.cfm --->
<cfoutput>#msg#</cfoutput><br>

Wednesday, 17 April 2013

Installing ColdFusion 5 (yeah, that's not a typo) on Windows 7 64-bit

G'day:
This is not exactly what I was intending to do this morning, but - as is often the case - a question on Stackoverflow piqued my interest. In this case, a person needs to get CF5 running on Windows Server 2008 R2, and - seemingly - was having some problems, supposedly with the 64-bitness of their OS.

I have the CF5 installer lying around here somewhere, so I decided to see if I could get it to install on my Windows 7 64-bit laptop. I reckon if it installs on Windows 7, there's a good chance of it installing on on Windows Server too.

Monday, 8 April 2013

CFML: onApplicationStart will run whilst onApplicationEnd is still underway

G'day:
This is another article which comes on the back of research stemming from not knowing the answer to a Stackoverflow question. In this case the questioner had noticed that onApplicationStart() seems to re-run (so the application is restarting) whilst onApplicationEnd() from a previous application shutdown is still underway.


I figured this would be unfortunately if this was true, so decided to find out.

I knocked out this code:

// Application.cfc
component {

    this.name = "shutdownSequenceTest12";
    logIt("Begin Pseudoconstructor");
    this.applicationTimeout        = createTimespan(0,0,2,0);
    variables.sleepDuration        = 3000;
    sleep(variables.sleepDuration);
    logIt("End Pseudoconstructor");


    function onApplicationStart(){
        logIt("Begin onApplicationStart()");
        sleep(variables.sleepDuration);
        logIt("Mid onApplicationStart()");
        sleep(variables.sleepDuration);
        logIt("End onApplicationStart()");
    }

    function onRequestStart(){
        logIt("Begin onRequestStart()");
    }

    function onRequest(){
        include arguments[1];
    }

    function onRequestEnd(){
        sleep(variables.sleepDuration);
        logIt("End onRequestEnd()");
    }

    function onApplicationEnd(){
        logIt("Begin onApplicationEnd()");
        sleep(variables.sleepDuration * 3); // need some time to react
        logIt("Mid onApplicationEnd()");
        sleep(variables.sleepDuration * 3); // need some time to react
        logIt("End onApplicationEnd()");
    }
    
    function logIt(required String message){
        writeLog(file=this.name, text="#message# from @ #listLast(CGI.script_name, '/\')#");
    }

}

This basically emulates an app that takes some time to execute its various stages, so I can interleave requests and see how they run.

I then created two CFM templates:

<!--- normalRequest.cfm --->
<cfset logIt("Start requested template")>
<cfoutput>#now()#</cfoutput>

<!--- shutdownRequest.cfm --->
<cfset logIt("Start requested template")>
<cfoutput>#now()#</cfoutput>
<cfset applicationStop()>
<cfset logIt("End requested template")>

I use the former to "warm" the application, then use the latter to shut it down. Whilst the shutdown is in progress, I re-run the normalRequest.cfm, to see what happens.

Here's the resultant log file:

Begin Pseudoconstructor from @ normalRequest.cfm
End Pseudoconstructor from @ normalRequest.cfm
Begin onApplicationStart() from @ normalRequest.cfm
Mid onApplicationStart() from @ normalRequest.cfm
End onApplicationStart() from @ normalRequest.cfm
Begin onRequestStart() from @ normalRequest.cfm
Start requested template from @ normalRequest.cfm
End onRequestEnd() from @ normalRequest.cfm

Begin Pseudoconstructor from @ shutdownRequest.cfm
End Pseudoconstructor from @ shutdownRequest.cfm
Begin onRequestStart() from @ shutdownRequest.cfm
Start requested template from @ shutdownRequest.cfm
Begin onApplicationEnd() from @ shutdownRequest.cfm

Begin Pseudoconstructor from @ normalRequest.cfm
End Pseudoconstructor from @ normalRequest.cfm
Begin onApplicationStart() from @ normalRequest.cfm
Mid onApplicationStart() from @ normalRequest.cfm

Mid onApplicationEnd() from @ shutdownRequest.cfm
End onApplicationStart() from @ normalRequest.cfm
Begin onRequestStart() from @ normalRequest.cfm
Start requested template from @ normalRequest.cfm
End onRequestEnd() from @ normalRequest.cfm

End onApplicationEnd() from @ shutdownRequest.cfm
End requested template from @ shutdownRequest.cfm
End onRequestEnd() from @ shutdownRequest.cfm



Here the initial warming request is greyed out.

The next request is me requesting a shutdown, and whilst that's still running, I perform another normal request, which commences the application starting again. However the application is still in the process of being shut down from last time. Note that the stop/start event handler processing are intertwined there: the re-start actually finishes before the shutdown of the previous application is complete.

I think this is something to be aware of, and it makes a kind of sense.

Bear in mind that onApplicationStart() and onApplication() end are event handlers, not the events themselves. They do not represent the application starting or the application stopping, they are simply something that ColdFusion will fire off for us when it handles the start/stop process.

So if we were being dogmatic about things, then this is correct behaviour. However in reality, I think it's legitimate for a running onApplicationStop() process should block the next onApplicationStart() process, just like one won't get two almost concurrent requests both trying to run onApplicationStart() each: only the first one runs it, and the second one waits until the first one is done before proceeding (and by then the application is started, so that second request doesn't even try to run onApplicationStart() itself). I think there's a good case for onApplicationStop() to be synchronised with onApplicationStart().

I have not run this on Railo yet, but I will after I walk down to the park to get some coffee.

Thoughts?

Update: I've written a follow-up to this article, which shows how to resolve this issue.

--
Adam

Saturday, 6 April 2013

Overlapping requests will not cause a race condition in a CFM's variables scope

G'day:
This is mostly a follow-up from a Stackoverflow question. The question is based around some confusion arising from a blog article which offers some misinformation about how functions can cause race conditions across two requests simply by not VARing variables, or accessing the variables scope explicitly instead of using a function-local variable. To be very clear from the outset: the blog article is mostly wrong.

Monday, 1 April 2013

Integrating CF ORM into FW/1 and Stackoverflow bullying (mostly the latter)

G'day:
OK, so I sound a bit like a broken record with Stackoverflow, but they've rankled me even more than usual today. Someone's raised a pretty poorly-worded question (I am moderately confident English is not their first language though, so this can't be helped), but it was decipherable and one of the ColdFusion community's chief stalwart's - Scott Stroz - was helping the person out with his problems. Scott had posted an answer, and they were working back & forth to clarify the requirement, and making good headway.

And then one of the Stackoverflow moderators took it upon themselves to both close the question, as also delete Scott's answer.