Search code examples
spring-mvctimeoutspring-integration

spring-integration 5.5.18 messaging-gateway timeouts


I'm using @MessagingGateway in order to bridge between spring-mvc @Controller and spring-integration. The @MessagingGateway declaration looks like this:

package a.b.c;

import org.springframework.integration.annotation.*;
import org.springframework.stereotype.Component;

@MessagingGateway(name="inboundGateway" defaultRequestTimeout="2000"
                                        defaultReplyTimeout="2000")

@Component
public interace InboundGateway {

    @Gateway(requestChannel = "getSomething")
    Message<SomeValue> getSomething(@Headers Map<String, Object> headers);

}

which is referenced from a Controller

@Controller
@RequestMapping("/some/base/path")
public class SomeController {

    private final InboundGateway inboundGateway;

    public SomeController(InboundGateway inboundGateway) {
        this.inboundGateway = inboundGateway;
    }

    @GetMapping(value = "things", produces = { "application/json" })
    public ResponseEntity<SomeValue> getSomething(RequestContext<String> requestContext) {
        Message<SomeValue> response = inboundGateway.getSomething(requestContext);
        ....
}

I was thinking that the definitions of defaultRequestTimeout and defaultReplyTimeout would raise a timeout at the inboundGateway if the response was not returned within the specified time.

However, I'm seeing instead that the time used within the method getSomething() can surpass the specified time, in this example, 2 seconds. It seems that the 2 seconds is used as a timeout for the calls to downstream systems, but not as a timeout for the return from getSomething().

Am I understanding this correctly? Is there some simple, declarative way of managing the timeout at the inboundGateway level? Any pointers appreciated.


Solution

  • The behavior you explaining is typical for flows where your inboundGateway is a DirectChannel. This way the message process is performed directly on the thread producing that message. So, it cannot reach the replyTimeout for result since that thread is blocked waiting for message handling.

    See more info in docs for different channels: https://docs.spring.io/spring-integration/reference/channel/implementations.html

    Also see docs for those timeouts on the Gateway: https://docs.spring.io/spring-integration/reference/gateway.html

    As a simple solution for your expectation you may consider to use a QueueChnanel for that inboundGateway or an ExecutorChannel. This way the processing will be handed off to a different thread and gateway will be able easily move on to the reply waiting block. And that's where that replyTimeout will have an effect.

    It is also explained in that annotation attribute JavaDocs:

    /**
     * Provides the amount of time dispatcher would wait to send a {@code Message}. This
     * timeout would only apply if there is a potential to block in the send call. For
     * example if this gateway is hooked up to a {@code QueueChannel}. Value is specified
     * in milliseconds; it can be a simple long value or a SpEL expression; array variable
     * #args is available.
     * See {@link Gateway#requestTimeout()} for per-method configuration.
     * @return the suggested timeout in milliseconds, if any
     */
    String defaultRequestTimeout() default IntegrationContextUtils.DEFAULT_TIMEOUT_STRING;