Catching CFLock Timeout Errors In ColdFusion
When it comes to catching errors in a ColdFusion application, I typically use a custom error type or the "Any" type. But, today, I had to do something that I've never done before - catch a CFLock timeout. As it turns out, a lock-timeout is fairly easy to filter out of the myriad of errors that could be thrown in your application; it presents as with type, "Lock," and carries the lock name in the exception object.
When catching a CFLock timeout error, you obviously need to use a CFTry / CFCatch statement; but, in order to focus specifically on lock errors, you have to define a catch statement that targets the "Lock" type. To see this in action, take a look at the following code. Keep in mind that in lieu of long-running "business logic", I'm using the sleep() function:
<cfscript>
try {
// By default, the lock will throw an error if it times-out waiting for accesss.
// When it does, the exception type will be "Lock".
lock
name = "my-action-lock"
type = "exclusive"
timeout = 1
{
// .... code that could go wrong in a number of ways IN ADDITION to throwing
// a lock timeout error.
sleep( 8 * 1000 );
} // END: Lock.
} catch ( "Lock" error ) {
// Make sure the lock error is the one we "know" about and NOT coming from
// something father down in the stacktrace.
if ( error.lockName != "my-action-lock" ) {
rethrow;
}
// Translate the lock timeout into an error that is easier for your application
// to consume in the calling context.
throw(
type = "BenNadel.PendingConflict",
message = "You have already initiated this action (but it has not yet completed)."
);
}
</cfscript>
Inside the CFCatch statement, we need to make sure that we're dealing with the right error. It's possible that our business logic has some encapsulated locking code that also raises an exception. In such a case, we need to make sure we're not reacting to the wrong error. If the lock name doesn't match "our" lock statement, simply rethrow the error.
I want to do this in order to provide the calling context with an error that was more meaningful. If I let the native error bubble-up, it may not be reasonable for the calling context to make assumptions as to why the error occurred; but, if I throw the application-specific error, "BenNadel.PendingConflict", it gives the calling context something very specific to catch (and potentially report back to the user).
Want to use code from this post? Check out the license.
Reader Comments
Hi Ben:
It's probably a bit OTT to be checking the lock name in this example, as there's only one possible lock it could be. Your tactic would make more sense if there were multiple locks in the same one try/catch.
--
Adam
@Adam,
Right, for the code show, it doesn't really make much sense. My only concern was that if the sleep() statement was replaced with something like:
someService.doSomething()
... it's possible that there might be something in the invoked code that *also* throws a lock-timeout that I was not aware of or was not expecting. In that case, I didn't want to accidentally report the wrong timeout error.
And, like I said, this if the first time I've ever actually caught a lock-timeout; so, it's entirely possible that in my application code, I will forgo the name-check as I *do* know what code is actually executing.
Ben,
How do I subscribe to your blog?
Right now I have an IFTTT recipe to email me whenever there's a new feed item, but that seems a bit kludgy.
And Google Reader has been discontinued.
@Phillip,
Right now, there's no way to subscribe to the blog itself - only to a given post (by posting a comment). I'll add it on my ToDo list as something to look into :)
If you follow @CfmlNotifier on Twitter, I send out a status update whenever the ColdFusion Bloggers RSS feed updates.
That covers your stuff, Ben.
--
Adam
@Phillip,
You could also follow @BenNadel on Twitter. He generally announces all of these blog posts there.
@Adam,
Followed :)