While perusing one of my email lists I stumbled onto a behavior of the "isDefined()" function that bears repeating. This function is commonly used in most ColdFusion applications. In fact, I would put it in the top 10 of functions used (perhaps the top 5), so any bug or interesting behavior related to isDefined( ) should warrant some notice. The short description of the problem is that isDefined() may throw an exception during a lengthy request. The conditions have to be just right.
If you are wondering if this behavior is related to an error you are experiencing, one clue is in the exception information. If you are seeing something like "error Error while reading header [VARNAME]" in conjunction with a socket write error (connection reset by peer: socket write error) then you should probably take a closer look at this post.
But before we discuss the behavior, it's important to understand how "isDefined()" works. As you know everything in ColdFusion belongs to some scope or is a member of some object. So ColdFusion has to work it's way down an order of precedence when trying to figure out if something is defined or not. Something like this.
What our little play illustrates is that ColdFusion has to look through a complete list of scopes when using isDefined(). In fact, isDefined() takes no notice of your dotted notation unless the first part of the string matches the scope it is examining at the time. Time for an Example:
Although its been said many times many ways (with my apologies to Johnny Mathis) it bears repeating that isDefined() will not perform as efficiently as structkeyExists(). StructKeyExists() has an easier time of it because the code must identify a scope or structure for the function to examine. For isDefined() to work you throw it some string and say "figure it out and get back to me" - which naturally takes more steps and is more time consuming.
Secondly, when you use dotted notation (i.e. isDefined('form.giJoe')), the left hand side only matters if the parser gets around to that scope. For each scope it examines isDefined takes a peak at the left hand side and determines if it's the same name as the scope in question. So simply doing something like this:
Now back to our error. Remember I said it had to be a lengthy request. Indeed for this particular error to crop up, the requests needs to be running long enough for the connection between JRUN and the web server to be dropped. So, for example (and this is pure conjecture), say a database query hangs for a long time and the web server gives up drops the connection to JRUN. JRUN is still drumming its fingers (or "digits" I suppose) and when it finally gets the query return from the DB server it moves to the next task - an "isDefined()" call. Remember our order of precedence?
When the isDefined() routine gets to scope number 6 in its order it is going to try and access the CGI scope. The CGI scope is contained in a reference or header - something provide by the web server... the web server that has now moved on to bigger and better things. When it tries to sort through the CGI information it can't "read" from the information that it expected to be there because the web server no longer has an open connection with this particular request. So it throws the sort of exception that you might expect - a "socket error" (Connection reset by peer: socket write error) and an "Error while reading header" error. Jrun is trying to send a message to the web server so it can examine the CGI scope, and it fails because the socket it closed or the memory dereferenced or whatever.
I'm told this condition has been around since CFMX. It seems like something that could be addressed by a fix to the connector, but I will leave it to Adobe to figure out if that is possible or not. Such an error will affect servers doing a lot of heavy lifting where there are potentially long running requests. Of course, many folks (myself included) will say that isDefined( ) should be used quite sparingly and that structKeyexists() is the right way to go 99 percent of the time. Still, a host of legacy code and procedural programming that is still in the wild means we will be dealing with isDefined() issues for the foreseeable future. So Adobe if you are listening, it makes sense to fix this issue.
You might see a flurry of these sort of errors after something has managed to hang or queue a group of threads on your ColdFusion server. For example, if your DB is having performance issues it could result in queuing threads - threads waiting for the DB to return. When the threads start clearing out, some percentage of the JRUN connections to the web server will likely have been closed - resulting in errors if isDefined( ) is subsequently called. If you have had such performance issues check your log files. If you see a plethora of socket write errors you should consider some code refactoring to get rid of the offending isDefined() errors.
My thanks to CF Gurus Cameron Childress and Sean Corfield for helping to explain this behavior.