Non-blocking SOAP web services invocation

Imagine a scenario where your web application needs to call a SOAP web service to handle client requests. Reactive seems to be the word of the day lately. For that and many other actual reasons you’ll want the invocation to be non-blocking.

The situation would be much simpler if the service was implemented using REST instead of SOAP. Play Framework for example, would do all the hard work for you. No such luck – we’ll have to do some amount of work.

First steps

The obvious prerequisite for any reactive solution is that your application/web server needs to support asynchronous request handling. I will provide my solution in the context of Play Framework but you can choose any alternative. In classic Java (i.e. servlets) the situation would be a little more complicated – but even there you could use Spring MVC 3.2, for example.

Asynchronous JAX-WS

Then you need some SOAP client API. I will stick with the tried and tested JAX-WS and not venture into more experimental projects like scalaxb.

JAX-WS API supports asynchronous invocation. It works like this: when you generate the stub classes, you need to explicitly state that you want to generate methods for asynchronous invocation alongside the synchronous ones. You can look at an example of such generated Java interface here. Note the methods with names ending with “Async”.

Then you can invoke the service methods asynchronously by passing a callback to handle the eventual response. Since this is all Java API we need to get from there to a scala.concurrent.Future somehow. After that we’re golden – as far as Play is concerned.

You can look at my solution here. The JAX-WS async method is invoked with a handler that completes a Promise. The actual JAX-WS method invocation is passed to a helper method in a function. The helper method creates the handler, applies it to the passed-in function and returns a Future associated with the aforementioned Promise.

Asynchronous does not mean non-blocking

Are we done? Well, not yet. Now the Play’s request-processing threads are not blocked by web service method invocations. But what actually happens behind the covers when we invoke one of the asynchronous JAX-WS methods?

It actually depends on your JAX-WS implementation. The Oracle JRE’s default implementation is JAX-WS RI (reference implementation). This implementation manages its own thread pool and the real HTTP communication happens there. Unfortunately it uses the JDK’s vanila HTTP client that is (surprise, surprise) blocking.

So far, we’ve only moved the blocking operations from one thread pool to another – and that’s not reactive at all.

Non-blocking HTTP client and CXF

Lucky for us that there are other JAX-WS implementations. In the past I’ve had good experience with Apache CXF. Here we’ll take advantage of its ability to use a non-blocking HTTP client.

We just need to add two dependencies to our application:

  • cxf-rt-frontend-jaxws will make CXF the JAX-WS implementation in our application
  • cxf-rt-transports-http-hc will allow CXF to use the non-blocking HTTP client

Just the presence of these libraries in our application’s classpath will do the trick.

By the way, the HTTP client is not the same as the one Play uses. This one if from another Apache project: HTTP Components. It is based on Java NIO and the Reactor pattern described by Doug Lea. And if using a reactor is not reactive then I don’t know what is.

There’s always room for improvement

Now our application does not block threads to invoke the web service but there are still two issues I would like to point out.

JAX-WS is a little sneaky and will make a blocking HTTP GET of the service’s WSDL in the service’s constructor. I recommend making the service object global – certainly don’t create it for every invocation. You could also store the WSDL locally (as a classpath resource even) to keep its availability under your control. You can pass its URL to the service’s constructor.

The other issue is that the use of CXF and the non-blocking HTTP is assured only by a presence of certain JAR files on your application’s classpath. It would be prudent to check the actual JAX-WS implementation and the presence of the non-blocking HTTP client during application’s startup.

Article has 3 comments

  • Guido

    1
    Ta úvodní část se mi moc nelíbí - obsahuje tvrzení bez kontextu. Bylo by dobré aspoň zmínit doménu a pár ukotvujících informací. A pak teprve říct, že SOAP WS můžou být problém.

    Většinou je to spíš problém architektury a v pozadí tak nějak čtu, že její návrh nemáte až tak pod kontrolou.

    Od popisu rešení už je článek pěkný a líbí se mi, jak jde do hloubky.

    Obecně, pokud k tomu není důvod, je lepší mít WSDL lokálně, právě kvůli tomu jeho načítání.

    A ještě mě napadá jedna otázka. Celé mi to přijde jako postavené na dokumentaci/specifikaci. Dělali jste nějaké testy (performance, škálovatelnosti apod.), které by to fungování potvrdily?
  • Vlastimil Menčík

    2
    Ten článek (naštěstí) není založen na nějaké konkrétní aplikaci, která by skutečně musela (téměř) pro každý request volat webovou službu. Proto také začíná slovy "představte si". Většinou se tomu dá nějak vyhnout, ale chtěl jsem řešit situaci, kdy by to prostě nebylo možné. Kontextem je tedy hypotetická frontend webová aplikace, která pomocí WS třetí strany přistupuje k datům, které zobrazuje (případně i mění).

    Tím pádem nemám ani změřená konkrétní čísla. Výhody neblokujícího IO při obsluze konkurentních requestů jsem považoval za dostatečně prokázané.

    Srovnáním klasického blokujícího přístupu s neblokujícím se zabývá např. tenhle článek: http://jazzy.id.au/default/2012/11/02/scaling_scala_vs_java.html
  • Juan Manuel Lopez

    3
    Hello, i have soap client create based on wsdl, i need to implement non blocking async, that service are consuming for many users. can you help me?