Details

    • Type: New Feature
    • Status: Closed
    • Priority: Minor
    • Resolution: Won't Fix
    • Affects Version/s: 2.2.0.RELEASE
    • Fix Version/s: 3.0.0.RC1
    • Component/s: Core
    • Labels:

      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.

        Activity

        Hide
        dariovmartine Victor Dario Martinez added a comment -

        Plans for add support to asynchronous web service invocations natively ?

        Show
        dariovmartine Victor Dario Martinez added a comment - Plans for add support to asynchronous web service invocations natively ?
        Hide
        gregturn Greg Turnquist added a comment -

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

        Show
        gregturn Greg Turnquist added a comment - Given this is new functionality, it doesn't fit the scope of version 2.3, so it has been reassigned to version 3.0.
        Hide
        marschall Philippe Marschall added a comment -

        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.

        Show
        marschall Philippe Marschall added a comment - 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 .
        Hide
        gregturn Greg Turnquist added a comment -

        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.

        Show
        gregturn Greg Turnquist added a comment - 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.
        Hide
        marschall Philippe Marschall added a comment -

        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.

        Show
        marschall Philippe Marschall added a comment - 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: create SOAP request and marshal it into a buffer/byte array/ByteArrayOutputStream send the buffer using the async/reactive HTTP client register an observer for the async/reactive HTTP client (should obviously happen before, just here for reasoning) if there's an error notify the other observers if the response is completely received into a buffer unmarshal it from the buffer 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: receive the SOAP request into a buffer/byte array/ByteArrayOutputStream unmarshal the request form the buffer start the pipeline (normal processing in the endpoint) register an observer for the pipline (should obviously happen before, just here for reasoning) create the SOAP response form the pipeline result and marshal it into a buffer/byte array/ByteArrayOutputStream write the buffer using the async/reactive server 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.
        Hide
        gregturn Greg Turnquist added a comment -

        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.

        Show
        gregturn Greg Turnquist added a comment - 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.
        Hide
        marschall Philippe Marschall added a comment -

        Fair enough

        Show
        marschall Philippe Marschall added a comment - Fair enough
        Hide
        victormartinez Victor Dario Martinez added a comment -

        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.

        Show
        victormartinez Victor Dario Martinez added a comment - 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.
        Hide
        gregturn Greg Turnquist added a comment -

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

        Show
        gregturn Greg Turnquist added a comment - Since this issue has been hashed out, I'm closing the issue.

          People

          • Assignee:
            gregturn Greg Turnquist
            Reporter:
            matsev Mattias Severson
          • Votes:
            7 Vote for this issue
            Watchers:
            9 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: