github twitter linkedin
Dropwizard 0.80 breaks your transaction handling
2015-03-07

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.


Back to posts