I was recently surprised to find that the finally block in this play framework controller action code only got called after an Exception, but never when the call actually succeeded.
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
Perhaps the thread is terminated or something when renderBinary() is called, but to me, it was non-intuitive. I would suspect the same thing happens for other render() calls, but I didn't verify it.
I solved the problem by moving the renderBinary() to after the try/catch. Further investigation revealed that play provides an @Finally annotation to create a method that gets executed after a controller action executes. The caveat here is that this will get called after the execution of ANY action in the controller, so it may not always be a good choice.
My question is: why does the finally block not get executed after a renderBinary(), and is this documented anywhere? I can't find any reference to it in the play doc.
To clarify the sequence of events that led to this discovery:
The files that were supposed to be deleted as a result of the finally block were not deleted.
Thinking that it couldn't possibly be caused by a non-executing finally block, I changed the methodology to use the Amazon SQS Messaging Queue to send a message in the finally block -- a separate job receives the message and deletes the associated files.
The messages were not getting sent.
I set breakpoints in the code and determined that renderBinary was being called, but the finally block was not getting executed.
Just to be safe, I added log messages to the finally clause, and these also were not present.
I have repeated the debug exercise several times, and each time, the finally clause is not executed.
(Please note that the actual code doesn't really look like the above. This is a very simplified example just to illustrate the case.)
It's true. I just found out about this today, since my company uses the play
framework and someone ran into it.
As I understand it, this likely only occurs in play
versions prior to 2.0, but when you catch all Exceptions following a render call, play
apparently rewrites the code to skip the finally
block...
I don't understand why or exactly how this is done, but it is apparently the case.
If you catch a specific exception, I don't think this will happen.
But yes, you're not crazy or a bad programmer. This really is just a weird, undocumented play
gotcha.