GetTempFile() Creates 0KB Files In ColdFusion
The other day, I happened to notice that a few of our servers had thousands of 0KB files in the temp-directory. After I was able to track down the code that was creating the temp files, I quickly realized what the problem was - the developer thought that the getTempFile() function simply returned a temporary file path; he was not aware (or was not thinking about the fact) that getTempFile() actually creates a file, albeit 0-bytes in size, when called.
The code that I found looked something like this:
<cfscript> | |
/** | |
* I do some processing with some temporary files. | |
* | |
* @output false | |
*/ | |
public void function processRequest( required numeric input ) { | |
// Get a scratch file in the temp directory that we can use to process the input. | |
var tempFilePath = getTempFile( getTempDirectory(), "processing-#input#-" ); | |
lock | |
name = "processingRequest" | |
type = "exclusive" | |
timeout = 1 | |
{ | |
try { | |
// Do some processing that may cause the parent LOCK to timeout on | |
// subsequent requests. | |
sleep( 5 * 1000 ); | |
// No matter what happens, clean up the scratch file. | |
} finally { | |
fileDelete( tempFilePath ); | |
} | |
} // END: Lock. | |
} | |
// ------------------------------------------------------ // | |
// ------------------------------------------------------ // | |
processRequest( 4 ); | |
</cfscript> |
As you can see, the code makes a good effort to clean-up after itself, deleting the scratch file in the Finally clause of the Try/Catch block. And, if you thought that getTempFile() only returned a file path, this would likely be sufficient. But, since getTempFile() actually creates a file and returns the resultant path, this code has the potential to leave scratch files laying around.
Once you concentrate on the fact that getTempFile() creates a file, it becomes clear that if the control flow can't obtain the Lock, due to the timeout, then the Try/Catch block is never entered. And, if the Try/Catch block is never entered, the Finally block is never executed which means that the temp file is never cleaned-up.
This is what was happening in our code. Luckily, the fix is quite easy - all we have to do is move the getTempFile() request into the Try/Catch block. Doing so will ensure that the temp file only ever gets created in a context that can be cleaned-up:
<cfscript> | |
/** | |
* I do some processing with some temporary files. | |
* | |
* @output false | |
*/ | |
public void function processRequest( required numeric input ) { | |
lock | |
name = "processingRequest" | |
type = "exclusive" | |
timeout = 1 | |
{ | |
try { | |
// Get a scratch file in the temp directory. | |
var tempFilePath = getTempFile( getTempDirectory(), "processing-#input#-" ); | |
// Do some processing that may cause the parent LOCK to timeout on | |
// subsequent requests. | |
sleep( 5 * 1000 ); | |
// No matter what happens, clean up the scratch file. | |
} finally { | |
fileDelete( tempFilePath ); | |
} | |
} // END: Lock. | |
} | |
// ------------------------------------------------------ // | |
// ------------------------------------------------------ // | |
processRequest( 4 ); | |
</cfscript> |
It's a minor change, but it makes all the difference. Ultimately, though, you just have to realize that the getTempFile() function both creates a file and returns a file path.
Want to use code from this post? Check out the license.
Reader Comments