Handle exceptions/errors other than MessagingException ie.., other error/exception which are not wrapped as MessagingException in spring-integration

huangapple go评论78阅读模式
英文:

Handle exceptions/errors other than MessagingException ie.., other error/exception which are not wrapped as MessagingException in spring-integration

问题

以下是您提供的代码部分的翻译:

在 Spring Integration 中,我的代码故意抛出 SourceAssertionError。在 spring-integration 的 5.1.6.release 版本中,对于任何错误,之前在 RequestHandlerRetryAdvice 中,无论出现什么错误,都会将其包装在 MessagingException 中。在 RequestHandlerRetryAdvice 的 doInvoke() 方法中如下所示:

@Override
protected Object doInvoke(final ExecutionCallback callback, Object target, final Message<?> message)
        throws Exception {
    RetryState retryState = null;
    retryState = this.retryStateGenerator.determineRetryState(message);
    messageHolder.set(message);

    try {
        return this.retryTemplate.execute(context -> callback.cloneAndExecute(), this.recoveryCallback, retryState);
    }
    catch (MessagingException e) {
        if (e.getFailedMessage() == null) {
            throw new MessagingException(message, "Failed to invoke handler", e);
        }
        throw e;
    }
    catch (Exception e) {
        throw new MessagingException(message, "Failed to invoke handler", unwrapExceptionIfNecessary(e));
    }
    finally {
        messageHolder.remove();
    }
}

但是在 5.3.2.Release 版本中,现在不再将其包装在 MessagingException 中,而是作为 ThrowableHolderException 抛出,如下所示:

@Override
protected Object doInvoke(final ExecutionCallback callback, Object target, final Message<?> message) {
    RetryState retryState = this.retryStateGenerator.determineRetryState(message);
    MESSAGE_HOLDER.set(message);

    try {
        return this.retryTemplate.execute(context -> callback.cloneAndExecute(), this.recoveryCallback, retryState);
    }
    catch (MessagingException e) {
        if (e.getFailedMessage() == null) {
            throw new MessagingException(message, "Failed to invoke handler", e);
        }
        throw e;
    }
    catch (ThrowableHolderException e) { // NOSONAR catch and rethrow
        throw e;
    }
    catch (Exception e) {
        throw new ThrowableHolderException(e);
    }
    finally {
        MESSAGE_HOLDER.remove();
    }
}

现在,在进行 spring-integration 升级后,我的代码流程变为错误(非 MessagingException)不会被路由到错误通道。在 RequestRetryHandlerAdvice 中的 doInvoke() 方法抛出的异常在路由到错误通道之前被拒绝,因为逻辑要求它们是特定类型,即如果异常仅为 MessagingException,则将其路由到错误通道。在 5.3.2.Release 版本中,与升级前不同,我的错误已被包装为 MessagingException,并且流程一直到达 MessagingGatewaySupport 中的 handleSendAndReceiveError(..) 方法,在该方法中通常会被路由到自定义定义的错误通道。但在升级后,流程在此之前就已经结束了。

我的 Spring 配置非常简单,我只定义了一个自定义的错误通道,仅用于网关。

<int:gateway id="gateway" error-channel="myErrorChannel" />

另外,我为此错误通道定义了一个转换器。现在我的问题是如何处理此错误?我是否可以通过将其路由到新定义的错误通道来处理,或者是否可以将其处理到已经定义的 myErrorChannel?

编辑 1:如 Artem Bilan 所要求,添加配置文件。

<bean id="myPreferences" class="package.MyPreferences" />
<bean id="myExceptionTransformer" class="package.myExceptionTransformer" />
<int:channel id="myErrorChannel" />
<int:transformer input-channel="myErrorChannel" ref="myExceptionTransformer" />
<bean id="Logger" class="package.Logger" />

<int:gateway id="gateway" error-channel="myErrorChannel"
    service-interface="package.myClient"
    default-request-channel="myRoutingChannel">
    <!-- 方法配置 -->
</int:gateway>

<int:publish-subscribe-channel id="myRoutingChannel" />

<int:header-value-router input-channel="myRoutingChannel"
    header-name="#{T(package.AppContext).REQUEST_TYPE}">
    <int:mapping value="#{T(value1)}" channel="authGatewayChannel" />
    <int:mapping value="#{T(value2)}" channel="provGatewayChannel" />
</int:header-value-router>

<int-ws:request-handler-advice-chain>
    <ref bean="provRetryAdvice" />
</int-ws:request-handler-advice-chain>
</int-ws:outbound-gateway>

<bean id="provRetryAdvice" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
    <!-- 配置 -->
</bean>

我的转换器定义如下:

@Transformer
public Message<?> transformErrorToResponse(Message<?> exceptionMessage) {
    // 转换逻辑
    return errorMessage;
}

这些是您提供的代码部分的翻译。如果您有关于代码部分的任何问题,请随时问我。

英文:

My code deliberately throws a SourceAssertionError. Earlier in 5.1.6.release of spring-integraton for any error , in RequestHandlerRetryAdvice, for any error, it would wrap it in MessagingException. In Below doInvoke() of RequestHandlerRetryAdvice,

@Override
	protected Object doInvoke(final ExecutionCallback callback, Object target, final Message&lt;?&gt; message)
			throws Exception {
		RetryState retryState = null;
		retryState = this.retryStateGenerator.determineRetryState(message);
		messageHolder.set(message);

		try {
			return this.retryTemplate.execute(context -&gt; callback.cloneAndExecute(), this.recoveryCallback, retryState);
		}
		catch (MessagingException e) {
			if (e.getFailedMessage() == null) {
				throw new MessagingException(message, &quot;Failed to invoke handler&quot;, e);
			}
			throw e;
		}
		catch (Exception e) {
			throw new MessagingException(message, &quot;Failed to invoke handler&quot;, unwrapExceptionIfNecessary(e));
		}
		finally {
			messageHolder.remove();
		}
	}

but now in 5.3.2.Release, its not wrapped in MEssagingException but rather thrown as THrowableHolderException as seen below

@Override
	protected Object doInvoke(final ExecutionCallback callback, Object target, final Message&lt;?&gt; message) {
		RetryState retryState = this.retryStateGenerator.determineRetryState(message);
		MESSAGE_HOLDER.set(message);

		try {
			return this.retryTemplate.execute(context -&gt; callback.cloneAndExecute(), this.recoveryCallback, retryState);
		}
		catch (MessagingException e) {
			if (e.getFailedMessage() == null) {
				throw new MessagingException(message, &quot;Failed to invoke handler&quot;, e);
			}
			throw e;
		}
		catch (ThrowableHolderException e) { // NOSONAR catch and rethrow
			throw e;
		}
		catch (Exception e) {
			throw new ThrowableHolderException(e);
		}
		finally {
			MESSAGE_HOLDER.remove();
		}
	}

Now after spring-integration upgrade my code flow goes in such a way that error(Not MessagingException) is not being routed to error-channel. The exception thrown by doInvoke() in RequestRetryHandlerAdvice is rejected before its routed to error channel because the logic required them to be of particular type i.e., if only the exception is MessaginException then its routed to error-channel. The flow exits with exception thrown by rethrowExceptionCauseIfPossible(..) in GatewayProxyFactoryBean. Before upgrade my error had been wrapped to MessagingException and flow reaches till handleSendAndReceiveError(..) in MessagingGatewaySupport where it usualy is routed to custom defined error-channel. This is not happening after upgrade to 5.3.2.Release as flow ends before itself

my spring configuration is very straightforward, I just have one custom error channel defined only to gateway.

<int:gateway id="gateway" error-channel="myErrorChannel". and defined a transformer for this error-channel

Now my question is how can I handle this error? is there anyway I could handle it by routing to any newly defined error-channel or can I do it to my already defined myErrorChannel?

EDIT1: Adding config file as Artem Bilan Requested

	&lt;bean id=&quot;myPreferences&quot; class=&quot;package.MyPreferences&quot; /&gt;
	&lt;bean id=&quot;myExceptionTransformer&quot;
		class=&quot;package.myExceptionTransformer&quot; /&gt;
	&lt;int:channel id=&quot;myErrorChannel&quot; /&gt;
	&lt;int:transformer input-channel=&quot;myErrorChannel&quot;
		ref=&quot;myExceptionTransformer&quot; /&gt;
	&lt;bean id=&quot;Logger&quot; class=&quot;package.Logger&quot; /&gt;

	&lt;int:gateway id=&quot;gateway&quot; error-channel=&quot;myErrorChannel&quot;
		service-interface=&quot;package.myClient&quot;
		default-request-channel=&quot;myRoutingChannel&quot;&gt;
		&lt;int:method name=&quot;invokeAuthenticationRequest&quot;&gt;
			&lt;int:header
				name=&quot;#{T(name1)}&quot;
				value=&quot;#{T(value1)}&quot; /&gt;
		&lt;/int:method&gt;
		&lt;int:method name=&quot;invokeProvRequest&quot;&gt;
			&lt;int:header
				name=&quot;#{T(name2)}&quot;
				value=&quot;#{T(value2)}&quot; /&gt;
		&lt;/int:method&gt;
	&lt;/int:gateway&gt;

	&lt;int:publish-subscribe-channel id=&quot;myRoutingChannel&quot; /&gt;

	&lt;int:header-value-router input-channel=&quot;myRoutingChannel&quot;
		header-name=&quot;#{T(package.AppContext).REQUEST_TYPE}&quot;&gt;
		&lt;int:mapping
			value=&quot;#{T(value1)}&quot;
			channel=&quot;authGatewayChannel&quot; /&gt;
		&lt;int:mapping
			value=&quot;#{T(value2)}&quot;
			channel=&quot;provGatewayChannel&quot; /&gt;
	&lt;/int:header-value-router&gt;

	
		&lt;int-ws:request-handler-advice-chain&gt;
			&lt;ref bean=&quot;provRetryAdvice&quot; /&gt;
		&lt;/int-ws:request-handler-advice-chain&gt;
	&lt;/int-ws:outbound-gateway&gt;

	
	&lt;bean id=&quot;provRetryAdvice&quot;
		class=&quot;org.springframework.integration.handler.advice.RequestHandlerRetryAdvice&quot;&gt;
		&lt;property name=&quot;retryTemplate&quot;&gt;
			&lt;bean class=&quot;org.springframework.retry.support.RetryTemplate&quot;&gt;
				&lt;property name=&quot;backOffPolicy&quot;&gt;
					&lt;bean class=&quot;org.springframework.retry.backoff.FixedBackOffPolicy&quot;&gt;
						&lt;property name=&quot;backOffPeriod&quot; value=&quot;4000&quot; /&gt;
					&lt;/bean&gt;
				&lt;/property&gt;
				&lt;property name=&quot;retryPolicy&quot;&gt;
					&lt;bean class=&quot;org.springframework.retry.policy.SimpleRetryPolicy&quot;&gt;
						&lt;property name=&quot;maxAttempts&quot; value=&quot;#{provisioningRetryCount.intValue()}&quot; /&gt;
					&lt;/bean&gt;
				&lt;/property&gt;
			&lt;/bean&gt;
		&lt;/property&gt;
	&lt;/bean&gt; 

And my Transformer is defined as

@Transformer
	public Message&lt;?&gt; transformErrorToResponse(Message&lt;?&gt; exceptionMessage) {

		Object exceptionMessagePayload = exceptionMessage.getPayload();
		Throwable cause = ((MessagingException) exceptionMessagePayload).getCause();
newPayload = new myException(msg);

		/*add headers*/
		return errorMessage;
	}

	

答案1

得分: 1

"regression"的处理已经通过此更改完成:https://github.com/spring-projects/spring-integration/commit/b187bca36e2565e80e72e662c204a57c05aab11d。

因此,是的,我们不再针对常规异常抛出MessagingException包装,以避免不必要的较大堆栈跟踪。

我不太确定您的异常如何无法到达该错误通道。MessagingGatewaySupport中的代码如下:

    try {
        ...
        reply = this.messagingTemplate.sendAndReceive(channel, requestMessage);
        ...
    }
    catch (Exception ex) {
        ...
        reply = ex;
        ...
    }

    if (reply instanceof Throwable || reply instanceof ErrorMessage) {
        Throwable error =
                reply instanceof ErrorMessage
                        ? ((ErrorMessage) reply).getPayload()
                        : (Throwable) reply;
        return handleSendAndReceiveError(object, requestMessage, error, shouldConvert);
    }

可能是您错误处理程序中的逻辑仅检查接收到的ErrorMessage中的MessagingException,这种情况不再适用...

我们可以查看您的配置,以确保发生了什么,并可能复现以引导您找到适当的解决方案吗?

英文:

The "regression" has been done with this change: https://github.com/spring-projects/spring-integration/commit/b187bca36e2565e80e72e662c204a57c05aab11d.

So, yes, we don't throw a MessagingException wrapper for regular exceptions any more to avoid bigger stack trace for nothing.

I'm not fully sure how your exception cannot reach that error channel. The code in the MessagingGatewaySupport is like this:

    try {
        ...
        reply = this.messagingTemplate.sendAndReceive(channel, requestMessage);
        ...
    }
    catch (Exception ex) {
        ...
        reply = ex;
        ...
    }

    if (reply instanceof Throwable || reply instanceof ErrorMessage) {
        Throwable error =
                reply instanceof ErrorMessage
                        ? ((ErrorMessage) reply).getPayload()
                        : (Throwable) reply;
        return handleSendAndReceiveError(object, requestMessage, error, shouldConvert);
    }

Probably the logic in your error handler to check only for the MessagingException in the received ErrorMessage which is not the case any more...

May we see your configuration to be sure what is going on and maybe reproduce to lead you to the proper solution?

huangapple
  • 本文由 发表于 2020年10月21日 12:58:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/64456946.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定