0
votes

I'm trying to understand how errors should be handled in Spring Integration. I found documentation about errorChannel, I tried to use it but the exception is not caught.

Here is my HTTP outbound gateway:

<int-http:outbound-gateway id="orderRequestHttpGateway"
                               request-channel="orders-channel"
                               url="${url}"
                               http-method="POST"
                               expected-response-type="java.lang.String"
                               reply-timeout='5000'
                               reply-channel='pushed-channel'
                               charset="UTF-8">
</int-http:outbound-gateway>

I don't understand where I should catch exceptions thrown by this component (like a 500 HTTP error)

The route is started by a poller. I tried adding an error-channelproperty:

<int:inbound-channel-adapter channel="orders-trigger-channel" expression="''">
        <int:poller fixed-delay="${poller}" error-channel="errorChannel"/>
</int:inbound-channel-adapter>

I tried with a custom error channel. I also tried to override the existing errorChannel:

<int:channel id="errorChannel"/>
<int:outbound-channel-adapter id="errorChannelHandler"
                               ref="errorManager"
                               method="foo"
                               channel="errorChannel"/>

So far I keep getting MessageHandlingException and I can't catch them to deal with them properly.

2

2 Answers

1
votes

You catch exception only in the caller thread or in the place where you have a try...catch - there is nothing different in Spring Integration from pure Java: we catch exception whenever we have a try...catch.

According your description, the error-channel="errorChannel" on the <poller> is the way to go and if you don't have any other thread shifting downstream, such a MessageHandlingException is really thrown to the poller and wrapped into the ErrorMessage to be sent to that errorChannel configured.

It is a MessageHandlingException because we deal with the Messaging in Spring Integration and such an exception carries some context and important information about the flow and failed message. Your 500 HTTP error is just a cause in that message. So, when you catch and handle an ErrorMessage you should take a look into its stack trace for the information to parse.

On the other hand you can narrow a scope for the error handling via ExpressionEvaluatingRequestHandlerAdvice or RequestHandlerRetryAdvice: https://docs.spring.io/spring-integration/docs/5.0.6.RELEASE/reference/html/messaging-endpoints-chapter.html#message-handler-advice-chain

0
votes

Int-http:outbound-gateway has error-handler by default,You can use this error-handler to handle error of out bound. in your example add error-handler to int-http:outbound-gateway with sample name of errorHandler class name like below:

<int-http:outbound-gateway id="orderRequestHttpGateway"
                               request-channel="orders-channel"
                               url="${url}"
                               http-method="POST"
                               expected-response-type="java.lang.String"
                               reply-timeout='5000'
                               reply-channel='pushed-channel'
                               charset="UTF-8"
                               error-handler="nameOfErrorHandler">
</int-http:outbound-gateway>

Then create new class with nameOfErrorHandler that extend DefaultResponseErrorHandler like below

@Component("nameOfErrorHandler")
public class NameOfErrorHandler extends DefaultResponseErrorHandler {
    public NameOfErrorHandler() {
    }

    public void handleError(ClientHttpResponse response) throws IOException {

        if (response.getStatusCode() == HttpStatus.BAD_REQUEST) {
            throw new AccessDeniedException("Custom Message");
        } else if (response.getStatusCode() == HttpStatus.FORBIDDEN) {
            throw new AccessDeniedException("Custom Message");
        } else if (response.getStatusCode() == HttpStatus.NOT_ACCEPTABLE) {
            throw new ChannelsLimitExceededException("Custom Message");
        } else if (response.getStatusCode() == HttpStatus.PROXY_AUTHENTICATION_REQUIRED) {
            throw new PerTransactionLimitExceeded("Custom Message");
        } else if (response.getStatusCode() == HttpStatus.REQUEST_TIMEOUT) {
            throw new DailyLimitExceededException("Custom Message");
        } else if (response.getStatusCode() == HttpStatus.CONFLICT) {
            throw new MonthlyLimitExceeded("Custom Message");
        } else if (response.getStatusCode() == HttpStatus.GONE) {
            throw new DuplicateReqIdException("Custom Message");
        } else {
            throw new AccessInternalException("Internal server error");
        }
    }
}

Note: This all throw new some exceptions catch by first error-channel defined in chain