Caution when using Play's TemporaryFile
Play! Framework provides several BodyParser
s out of the box to parse common HTTP request bodies. One of them is for file uploads. Since Play can't reasonably know what you're doing with the body, they can't aggressively delete the file after the result is returned. Their solution is to clean up the file when the variable is garbage collected, using Java's finalize—rarely seen in the Scala world. Since the TemporaryFile
is held inside request
(request.body: TemporaryFile
), this is usually reasonable since request
won't be GCed during the lifecycle of the request.
However, this can bite you when doing asynchronous file operations, such as image resizing then uploading to a CDN. Since your APIs typically deal in real File
s (instead of the wrapped TemporaryFile), you may assume you can safely pass request.body.file
around. As soon as request goes out of scope (usually, by returning to the client), that File
reference can be deleted out from under you. Since it's garbage collection that triggers this, it probably won't happen often, and will happen somewhat randomly.
Recently, I ran into this when trying to determine why around 1% of image uploads (which involve resizing to various sizes and uploading to S3) on Kifi were failing. Unfortunately, the file deletion seemed to always happen between two lines that couldn't have deleted it. After a couple hours, we noticed TemporaryFile's documented behavior. Sigh.
So, be very careful with TemporaryFile. If you would like Play to manage the File lifecycle, make sure you're done before request.file
can be GCed. If not, make a copy immediately, and then assume responsibility for file management yourself.
I would have preferred that Play immediately delete the file after the Action
returns, so at least behavior is consistent.