What I Learned Today - CFEXECUTE is not Unix-friendly

Update: Based on a conversation with Paul Kukiel, this issue does not seem to exist in Ubuntu Linux. Definitely confirmed in Solaris, unsure about other Unix flavors.

For the first time ever, I needed to use the oft-maligned CFEXECUTE tag on a project. I was developing an intranet application to track the health of about 30 Unix-based servers in real time, using a variety of metrics. The application also resides on a Unix server.

One of the metrics was to ping the servers to make sure they are up. That required the usage of CFEXECUTE to run a shell script I had written to do the task.

The first issue I found was that on Unix-based systems (OS X and Unix), the tag was not returning the ping results to me, even though I was using the variable attribute. The variable was empty. After hours of trying, I ended up writing the contents of the ping to a file to read. That led me to my second issue.

My first choice was to write to the virtual filesystem. The thought was that since I would be doing 30 pings every five minutes it would be best to not have to make all those writes to the disk. The problem that brought about was that if the ping took too long to finish, CFEXECUTE wasn't waiting around for the script to finish before moving on. If the server was down it could take up to 20 seconds for the ping failure to come back. Forcing the application to wait that long every time around wasn't the answer, so I had to step back and look at the solution again.

While focusing on other aspects of the application, I ran across the third and largest issue with CFEXECUTE - it's a resource killer of alarming degree on Unix. CFEXECUTE uses the fork() method to run processes. I have found the following warning (in various forms) on multiple blogs and message boards regarding this.

"Because of the way the fork() method was implemented on unix systems (which is what cfexecute calls under the hood to run the external process) it duplicates the amount of memory of the calling process to run the external process, which is crazy. So, for example, if your JRun process is currently taking up 1 GB of RAM (a pretty common JVM size), then cfexecute will run the external process using 1 GB of RAM, which will very quickly throw an Out of Memory exception."

I ran into this problem on our QA server, which only has 384MB of swap space free and only 4GB on onboard memory. Our JVM is set for 1GB minimum so there was no way CFEXECUTE would find the space needed to make the duplicate environment.

Once I learned about this, I quickly decided to pull CFEXECUTE altogether. Instead I have a cron job that runs once a minute and outputs the ping results for each server to a separate file on the hard disk, overwriting existing files to limit space usage. The application will read these files in, and they're real-time enough in that 3-4 updates will have been made to the ping statuses by the time the next background polling is done by the application to read in the files.

I now completely understand why so many hosting services disable this tag. In addition to the security risks inherent to it, the toll it can take on your server (unless it's loaded up big time in memory) just is not worth it when there are other options to solving the problem.

CF Admin Not Showing Settings?

I'm running into an odd issue with CF9 admin. I just updated my local development CF9 to the latest hotfix version using David Epler's great Unofficial Updater 2 Ant script, and I wanted to verify the changes had been made. When I logged into CF9 admin, and clicked the System Information icon, the page just kept hanging at the request phase.

Other pages in the CF admin work fine, and testing my sites CF is running fine.

Any thoughts on this?

UPDATE: I now can no longer access the Settings Summary page either.

Question on Managing 404 errors

I have a bit of an issue I was wondering if someone had an answer for.

I have a requirement to develop a custom 404 error handler to trap and handle 404 errors for CFM and CFC templates. That part is simple.

It also needs to still log the 404 error in the web server logs (Websphere/Apache) like it did before, for reporting purposes. That part is the sticking point.

First off, I found that setting a 404 error handler inside the CF admin will do one of two things, all based on what the error handler file does. In the first test case, the error handler logs the error in the CF logs, and then uses CFINCLUDE to display a styled error page. Because CF has now handled the file request with a fully working and existing template, it no longer tells the web server to log it as a 404 error. The web server now treats this as a 200 OK response.

Test case #2 is an error handler that logs the error, then uses CFLOCATION to send them to a safe place. Apache logs that as a 302 code for the redirect. It is interesting that CF can differentiate this, but there still is no way to alter this that I can determine.

I then took to setting up Apache's 404 error handling. I was able to get it to point to my CF 404 error handler template, which at first I thought would solve all the problems for non CFM/CFC templates. But then I found two major flaws in that.

Firstly all the Apache 404 error handler does is redirect the request to the error handler, again identifying it as a 302 status code instead of a 404.

The second issue is that it redirects the request so that CF has no way to get to the information regarding the file that was not found. When triggered through the CF admin 404 error handler, the error template has access to the CGI scope for the request to the missing file, which is how we properly log the request. Apache just does a redirect, leaving behind no CGI scope information that identifies the missing template. There is no HTTP_REFERER value, and the rest of the CGI scope refers to the error template itself, making it useless for us to use for logging.

And the Apache 404 error handler did NOT handle CFM or CFC files either. That surprised me.

So, I'm looking for any other options here to get it logged in the access_log file as a 404 while still handling and dealing with the error.

Thoughts?

CF9 on OS X Lion anyone? (update: it works)

I use my Macbook Pro daily as my primary development computer, and before I pull the trigger on upgrading to 10.7 Lion I need to know how CF9 will perform because I cannot afford any downtime. I cannot find anything on this on the net so far, it looks like nobody tested it out officially.

If anyone has upgraded to 10.7, can you please let me know what issues you had with ColdFusion 9 running on it?

My first concern was the lack of Java in Lion. Even with the capability to download Java for Lion I'm concerned that there will be problems.

If I wasn't using CF9 daily for my work, I'd be glad to be a guinea pig. But I don't have that luxury so I need others to be instead. :-)

Update: I installed Lion, and after installing Java for Lion have had no issues with CF9, MAMP Pro, or my MySQL and MSSQL databases. Only thing that happened to me was the internal IP address of my VMware Win7 instance changed, so I had to update the MSSQL datasources to use the new address.

What I Learned Today - createObject() has one big downside

Recently I talked about conforming to using init() methods in my components. I had planned to use createObject().init() to make the call in one nice quick line.

There's just one problem, createObject() won't work for me in my preferred site structuring.

I like to house all my application-level and session-level variables in separate include files in an includes/ directory beneath the web root. In Application.cfc, I call to those files in onApplicationStart() and onSessionStart(). It's a nice way for me to compartmentalize code and keep Application.cfc from getting too messy. I've done this for years now in dozens of sites.

I keep all my components in a components directory on the same level as the includes directory. I initialize the components in the application scope because they change so little (only when a code release is done) that it makes sense to keep them there to limit overhead by only creating the object one time.

Until recently I would use CFOBJECT to create the component variable. I would call it like this:

view plain print about
1<cfobject name="application.mySite.cfc.myComponent" component="components.myComponent" />

Never a problem. I try to change it to:

view plain print about
1<cfset application.mySite.cfc.myComponent = createObject("component","components.myComponent").init() />

and it blows up with the error "Could not find the ColdFusion component or interface components.myComponent".

For an hour I could not figure out why until digging enough showed me one huge difference between createObject() and CFOBJECT. While CFOBJECT is smart enough to know that the dot notation of the directory structure begins at the site root, createObject() only looks from the location of the template the call resides in. In this case it's the includes directory.

For kicks I added the createObject() call directly into the onApplicationStart() function in Application.cfc. It worked fine, confirming my lesson of the night that it has no capability to traverse up a directory structure, only down.

So it looks like I'll be sticking with CFOBJECT after all, at least until Adobe decides to give createObject() a little more flexibility. What stinks is that I'll have to make separate calls to the init() functions to get them run. Kinda defeats the purpose of them a little bit I think.

My embracing of the init() function

This entry comes from the "better late than never" department.

For years I have been coding with ColdFusion components. And for years I have resisted the calls to use an init() function, mainly because none of my components to date had ever been initializing anything. I would either pass in arguments to functions as needed, or I would use the application scope for things like datasources or file directories. It was one of those "What good is it?" type of deals.

Well, for the first time I am working on a project that I might decide to release out to the public if it goes as I hope. It's an error-handling project, based on methods I have been using for over six years now. So my thoughts have turned to how to make this portable, not just to my sites where I have a very consistent approach to coding but to others who probably code completely differently from me. I wanted to keep databases out of this project (what good is an error handler storing errors in a database if the database is the problem, and also as another way to make it portable) so I am using an XML file for configuration information. Where best to read this in? An init() function! Now I have my first need of it and am using it.

In the course of my research on best practices for using it, I ran across the Object Oriented ColdFusion site and their writeup on using init() had this in it:

"When you first create a new component the init() function may have no apparent need, but as your application grows you may find that your component changes and you need to initialise your objects into a particular state."

That struck a chord in me, and so from this point forward I am embracing the standards of using an init() function in every component I write, even if at the time it does nothing. I may be slow to change, but I'm not completely stubborn. Some of the time, at least.

Charting Software Recommendations Needed

A project I am working on makes extensive use of CFCHART. We have run into quite a few usage and performance issues with CFCHART, so I have been tasked to look at some third-party solutions to try out and recommend.

Anybody have some reviews and recommendations they'd care to share?

What I Learned Today - using CFCATCH as a struct

I've been working on a error handling application and ran into an issue. I could not pass along the CFCATCH scope as a struct as an argument. I could do it for any other scope. Testing revealed a weird oddity where ColdFusion does not see the CFCATCH scope as a struct.

Try this code

view plain print about
1<cftry>
2    <cfthrow type="Application" message="This is a test error">
3    <cfcatch type="any">
4        <cfoutput>#isStruct(cfcatch)#</cfoutput>
5        <cfset variables.copyOfCactch = duplicate(cfcatch) />
6        <cfdump expand="true" label="cfcatch" var="#cfcatch#" />
7        <cfoutput>#isStruct(variables.copyOfCactch)#</cfoutput>
8        <cfdump expand="true" label="variables.copyOfCactch" var="#variables.copyOfCactch#" />
9    </cfcatch>
10</cftry>

and this is what it returns:

NO YES

(plus the related dumps)

Q: When is CF 9.0.1 not CF 9.0.1?

A: When you're a moron and didn't install CF 9.0.1 properly.

I was working on some caching additions to an application when I noticed that using the expireURL attribute was not working correctly. It was removing the URL caches one at a time instead of removing them all. That made no sense to me because after reading Aaron West's blog tutorials on CF9 caching I knew CF 9.01 had fixed this.

An email to Aaron to try and troubleshoot this received a reply to check the version of my CF server. So I did. And it was still CF 9.0. Apparently I didn't do my upgrade properly way back when, and all this time I thought I had been developing on CF 9.0.1.

Don't I feel stupid.

ColdFusion Builder 2 Beta performance issues

I'm a big fan of the original ColdFusion Builder. I decided to give the CFBuilder 2 Public Beta a try. So far I love it, except for one nagging thing. The performance of this is so sluggish at times it makes it unusable. It will hit me with a "Refresh Content" notice with a high amount of regularity, sometimes multiple times inside of a minute. And during that time, performance slows to a crawl.

I did some looking around for solutions, but nothing so far has addressed this. I can run CFBuilder without issue. And my machine is more than capable of running both at the same time, but this happens even when I run it alone.

I run the standalone versions of both and am on OS X 10.6.

Anyone else running into this issue with the beta?

Comments are moderated solely for spam-prevention purposes.

More Entries