Dropwizard 0.8 has shipped. Unfortunately with broken transactions when using the hibernate module. I found this bug while migrating RESTwars to Dropwizard 0.80.
The behaviour should be:
- Start a transaction before a request is handled
- Commit the transaction if the request has been successfully handled
- Abort the transaction if the request failed with an exception
What happens instead is:
- Start a transaction before a request is handled
- Commit the transaction after the request has been handled, even if an exception has been thrown
This could have dire consequences, as your transaction will be committed even when an exception is thrown. Let’s look at this bug in detail:
@Override
public void onEvent(RequestEvent event) {
if (event.getType() == RequestEvent.Type.RESOURCE_METHOD_START) {
// ... code shortened ...
this.session = this.sessionFactory.openSession();
beginTransaction();
}
else if (event.getType() == RequestEvent.Type.RESOURCE_METHOD_FINISHED) {
if (this.session != null) {
// ... code shortened ...
commitTransaction();
this.session = null;
}
}
else if (event.getType() == RequestEvent.Type.ON_EXCEPTION) {
if (this.session != null) {
// ... code shortened ...
rollbackTransaction();
this.session = null;
}
}
}
This is a part of UnitOfWorkApplicationListener.java
. onRequest
is called when Jersey handles a request. To understand why the bug happens, take a look at the order in which Jersey emits events:
In case of no exception the order of events is:
MATCHING_START
REQUEST_MATCHED
REQUEST_FILTERED
RESOURCE_METHOD_START
RESOURCE_METHOD_FINISHED
RESP_FILTERS_START
RESP_FILTERS_FINISHED
FINISHED
In case of an exception the order of events is:
MATCHING_START
REQUEST_MATCHED
REQUEST_FILTERED
RESOURCE_METHOD_START
RESOURCE_METHOD_FINISHED
ON_EXCEPTION
EXCEPTION_MAPPER_FOUND
EXCEPTION_MAPPING_FINISHED
RESP_FILTERS_START
RESP_FILTERS_FINISHED
FINISHED
Dropwizard commits the transaction on RESOURCE_METHOD_FINISHED
and aborts the transaction on ON_EXCEPTION
. Unfortunately
RESOURCE_METHOD_FINISHED
is called before ON_EXCEPTION
, which means the transaction is committed in either case.
The fix is simple: Instead of handling the RESOURCE_METHOD_FINISHED
event, handle RESP_FILTERS_START
. In case of an
exception the transaction is aborted because ON_EXCEPTION
is called before RESP_FILTERS_START
.
This bug is fixed in Dropwizard 0.81.