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.
Reader Comments