REST with Asynchronous Jersey and RXJava – Part 4

By | December 29, 2016

In this series of articles I will implement a RESTful web service using Spring Boot and Jersey. I will then modify the service as to use asynchronous server-side request response processing and RXJava. Load tests will be made using Gatling before and after the modifications, in order to determine any improvements.

The first article in this series is available here, the second part here and the third part here.

In this fourth part in this series, I will first of all stand corrected. The Jersey features I have used in my example program does not enable asynchronous request processing, but asynchronous server-side response processing.

I will modify the example program as to use Jersey’s asynchronous server-side response processing and, as usual by now, load-test the modified version of the program. As in the previous article in this series, I will continue to use an external database with the exact same configuration.

Jersey Asynchronous Response Processing

Introducing Jersey’s asynchronous response processing requires smaller modifications compared to when introducing RXJava. The response is no longer created by the REST resource base class, but provided by Jersey as a parameter. This will not only reduce the amount of code but also fit in better with RXJava.

The Jersey asynchronous response processing means that there no longer is an I/O thread locked waiting for a response from a request processing method. Instead, the I/O thread may immediately return to the container, Tomcat in the case of my example program, while the processing of the request continues in another thread.

New Version of the REST Resource Base Class

First I will show the entire new version of the REST resource base class and then a detailed analysis will follow.

The method signatures and part of the implementation of all the methods annotated with HTTP verbs (@GET, @POST, @PUT and @DELETE) have changed. The in all of these methods are the same, so we’ll just have a closer look at one of these methods.

A Method Before and After Asynchronous Response Processing

Let’s compare the previous and the new versions of the getEntityById method. First, recall the previous version:

The new version looks like this:

Note that:

  • In the new version, the method return type is void.
    Since response processing is now asynchronous the result of a method is no longer to be returned but to sent to a response object, as we will shortly see.
  • In the new version, the method has an additional parameter – an AsyncResponse object.
    This is an object to which the response will be sent when the processing of the request has finished.
  • The additional parameter in the new version of the method is annotated with the @Suspended annotation.
    The @Suspended annotation tells Jersey that a new AsyncResponse object is to be injected into the annotated parameter whenever a request arrives bound for this method. The annotation also tells Jersey that the method is to be executed in an asynchronous fashion.
  • In the new version of the method, there is no longer any need to use the response container of the type AtomicReference.
    The AsyncResponse object is a final method parameter and thus readily available in the RXJava callback code blocks. Instead of storing the response object created in the RXJava callbacks, the response object can be sent back directly to the asynchronous response using the resume method.

Run Tests

To verify that these latest modifications hasn’t broken the program, we now run all the tests. Recall that the tests are TestNG tests – in my IDE there is a special alternative for running all the TestNG tests in a project.

Alternatively the tests can be run using Maven. In a terminal window, use the command:

All tests should pass.

Running the Load Test

It is now time for the load test once again to test on the new version of the REST service.

  • Start the example program.
    As usual, right-click the RestExampleApplication class and run it.
  • Run the Gatling load test in a terminal window.
    mvn gatling:test
  • Examine the Gatling load test report.

The text-version of the report obtained after my load-test looks like this:

These numbers are almost identical with the result from the load-test after having introduced RXJava in the previous article in this series. The graphs for this load test looks like this:

Load test response time distribution graph for the final version of the example program.

Load test response time distribution graph for the final version of the example program.

Load test responses per second graph for the final version of the example program.

Load test responses per second graph for the final version of the example program.

Why did we not achieve a better result from the load-test?
If one studies the Jersey documentation on the asynchronous server API, the following can be read:

“Note that the use of server-side asynchronous processing model will not improve the request processing time perceived by the client.”

So, why fiddle around with the Jersey asynchronous server API when it does not give us any improvements that can be perceived by the client?
While using an asynchronous processing model may not increase the performance, it does increase the robustness of the service. A service using a synchronous processing model that receives a high number of request may run out of threads to process the requests. This will result in requests failing. On the other hand, a service using an asynchronous processing model will not run out of resources as easily and be able to queue up more requests for processing. Requests may of course eventually time out if the service is not able to keep up the processing but that is another problem.

In my example program, the database is still as slow as ever and it is still the bottleneck so we can’t really expect any performance improvements.

Conclusion

So I wasted all this time fiddling around with RXJava and Jersey’s asynchronous response processing?

Personally, I do not think so. I have expanded my knowledge regarding load testing. I have learned to create more robust JAX-RS web services with Jersey. Finally, I have had a peek into RXJava, which I am sure I will get back to in the future.

This concludes this series of articles on REST with Jersey and RXJava. I hope you have learned something along the way.
As before, all the source-code is on GitHub. There is a “before” branch which shows the program before any changes were made. The “master” branch contains the final version of the example program with all modifications applied.

Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *