[SWS-882] AsyncWebServiceTemplate Created: 06/Oct/14  Updated: 16/Aug/17  Resolved: 16/Aug/17

Status: Closed
Project: Spring Web Services
Component/s: Core
Affects Version/s: 2.2.0.RELEASE
Fix Version/s: 3.0.0.RC1

Type: New Feature Priority: Minor
Reporter: Mattias Severson Assignee: Greg Turnquist
Resolution: Won't Fix Votes: 7
Labels: async, webservices
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

The existing WebServiceTemplate forces clients to perform blocking calls to the web service. With an AsyncWebServiceTemplate, the clients could execute non-blocking calls to the web service, thus potentially increasing the client's performance. A solution may also include changes to the WebServiceGatewaySupport class, or possibly involve creating a new AsyncWebServiceGatewaySupport class.

Compare with AsyncRestTemplate.



 Comments   
Comment by Victor Dario Martinez [ 13/Feb/15 ]

Plans for add support to asynchronous web service invocations natively ?

Comment by Greg Turnquist [ 19/Jan/16 ]

Given this is new functionality, it doesn't fit the scope of version 2.3, so it has been reassigned to version 3.0.

Comment by Philippe Marschall [ 01/Mar/17 ]

Ideally that integrates with the reactive support in Spring 5, e.g. by returning a Mono. So that a Spring 5 reactive application could use AsyncWebSericeTemplate.

Comment by Greg Turnquist [ 01/Mar/17 ]

Due to the nature of underlying SOAP providers to operate in classic synchronous fashion, this one is unlikely to get any motion.

A conciliatory option, though, is to do something like this:

Mono.fromRunnable(() -> {
    return webServiceTemplate.sendAndReceive(...)
})

This option lets you defer such an operation until the invoker is ready to subscribe, but the fact that underlying SOAP providers don't support reactive streams makes it impractical to expect Spring WS to provide full stack support for this.

Comment by Philippe Marschall [ 03/Mar/17 ]

Forgive me my superficial and probably naÏve view of things. Since SOAP in transport agnostic I don't expect the providers to have any hard coded dependencies to any HTTP clients. For the client I would expect an interaction similar to this:

  1. create SOAP request and marshal it into a buffer/byte array/ByteArrayOutputStream
  2. send the buffer using the async/reactive HTTP client
  3. register an observer for the async/reactive HTTP client (should obviously happen before, just here for reasoning)
    1. if there's an error notify the other observers
    2. if the response is completely received into a buffer unmarshal it from the buffer
      1. notify the receivers

This may not work if additional resources (e.g. schemas) are loaded over the network, the user has to disable that (which may be a good idea in general) and have to be able to provide them from memory.

And for the server:

  1. receive the SOAP request into a buffer/byte array/ByteArrayOutputStream
  2. unmarshal the request form the buffer
  3. start the pipeline (normal processing in the endpoint)
  4. register an observer for the pipline (should obviously happen before, just here for reasoning)
    1. create the SOAP response form the pipeline result and marshal it into a buffer/byte array/ByteArrayOutputStream
    2. write the buffer using the async/reactive server
    3. similar for errors

This may create additional memory churn if the current implementation uses streaming very well but that can be addressed with buffer management.

Comment by Greg Turnquist [ 03/Mar/17 ]

As I'm sure you can guess, it's a little more complex than that. There are multiple levels that have to be visited upon.

Because Spring WS's primary duty is to take the most popular 3rd party SOAP libraries and make them easier to use, it delegates a lot of tasks, like transforming SOAP payloads to/from their formats. That's why we have AxiomSoapMessage, SaajSoapMessage, etc. Since these operations don't have any form of reactive programming, that's a hit right there. To wrap all of them with reactive options would be a big effort, and not sure if it's pragmatic given we're just blocking on the results.

Then there is the job of transmitting the SOAP message over the wire. Spring WS is designed to support SOAP's protocol agnostic approach, hence we have lots of implementations of AbstractWebServiceConnection, delegating to things like JMS, XMPP, HttpConnection, etc. These protocols all have different semantics, so trying to capture an AbstractReactiveWebServiceConnection would take a bit of reasoning to see if it even makes sense, let alone the implementation details. Should JMS support reactive streams? What about XMPP? Given ClientHttpRequestConnection delegates to Spring's ClientHttpRequest interface, the implication that we could implement a reactive variant using Spring 5's APIs implies it would block here, and not ripple up the hierarchy.

Because SOAP isn't pinned on HTTP as a required transport mechanism, Spring WS doesn't have request/response in the same call. It makes a request, and later checks for a response. That right there would take a bit of design discussion to figure out the right approach to support reactive programming.

Simply put, SOAP and its myriad of specs and industry agreements makes it really hard to overhaul it to add reactive streams support. Fitting together two separate paradigms that weren't developed together would require a huge effort, and may not even be worth the effort. Reactive streams makes it possible to scale more efficiently by using resources better. Unless people are using SOAP on a Netflix-sized scope, it may simply be easier to build apps like this:

public Mono<List<Long>> reactivelyFindPayCheckAmount(String lastName) {
    return repository.findByLastName("Baggins")
        .flatMap(employee -> Mono.fromRunnable(e -> webServiceTemplate.sendAndReceive(...)))
        .map(soapEmployee -> soapEmployee.getPaycheckAmount())
        .collectList();

This lets you reactive build up a cohesive flow. The remote call to the older SOAP service holding payroll data is contained inside one step. If that remote SOAP service becomes a bottleneck, and may be useful to start to take it apart. But I wouldn't until it really became an issue.

In the meantime, attempting to make parts of Spring WS reactive when the entire core of SOAP itself wasn't built for it sounds like a lot of work with little benefit when you can hedge things as I have just shown.

Comment by Philippe Marschall [ 03/Mar/17 ]

Fair enough

Comment by Victor Dario Martinez [ 16/Aug/17 ]

CXF also has an HTTP client transport that is based on the Apache HTTP Components HttpAsyncClient library. Its Maven artifactId is cxf-rt-transports-http-hc. The HttpAsyncClient library uses a non-blocking IO model. This allows many more requests to be outstanding without consuming extra background threads.

Comment by Greg Turnquist [ 16/Aug/17 ]

Since this issue has been hashed out, I'm closing the issue.

Generated at Mon Dec 11 02:13:48 UTC 2017 using JIRA 6.4.14#64029-sha1:ae256fe0fbb912241490ff1cecfb323ea0905ca5.