我有一个网关实现如下。我在网关中定义了一个错误通道,以捕获整个SI流中的任何异常。 outputChannel将响应发送回网关。如您所见,使用拆分器和路由器创建的系统中有3个并行流。
在ErrorHandlingService中,我设置了相应的错误代码并将消息发送回aggregateDSLResponseChannel,以便整个流程顺利完成。我需要一个实现,其中整个流程在DSLFlowEndService中结束,即使存在异常,然后通过设置适当的响应对象将响应返回给调用者。原因是如果有连接请求说WLDP和IRIS并且说WLDP流失败但是IRIS成功了,我不想发送完整的响应作为失败。相反,我会向呼叫者发回适当的消息,提及部分成功(有失败和成功的详细信息)
为了测试,我在WLDPFlowEndService中引入了一个异常。异常来自错误通道,然后消息也会返回到aggregateDSLResponseChannel,然后返回到DSLFlowEndService。但是,响应不会发送回网关外部的呼叫者。基本上Spring集成流程永远不会完成,并且在配置后30秒后超时。以下是日志中的警告:
15:13:23.271 [dslParallelExecutor-2] WARN org.springframework.integration.core.MessagingTemplate$TemporaryReplyChannel {} - Reply message being sent, but the receiving thread has already received a reply:[Payload=DSLResponseVO
15:13:23.271 [dslParallelExecutor-2] DEBUG org.springframework.integration.channel.DirectChannel {} - postSend (sent=true) on channel 'outputChannel', message: [Payload=DSLResponseVO
**更新配置 - 一个有效(超级感谢Gary)**:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<int:channel id="inputChannel"></int:channel>
<int:channel id="outputChannel"></int:channel>
<int:channel id="dslFlowInitiatorOutputChannel"/>
<int:channel id="routingChannel"/>
<int:channel id="wldpInputChannel">
<int:dispatcher task-executor="wldpParallelExecutor" />
</int:channel>
<int:channel id="lcInputChannel">
<int:dispatcher task-executor="lcParallelExecutor" />
</int:channel>
<int:channel id="irisInputChannel">
<int:dispatcher task-executor="irisParallelExecutor" />
</int:channel>
<int:publish-subscribe-channel id="aggregateDSLResponseChannel"></int:publish-subscribe-channel>
<int:channel id="aggregateDSLOutputChannel">
<int:dispatcher task-executor="dslParallelExecutor" />
</int:channel>
<!-- all thread pools to execute tasks in parallel -->
<task:executor id="dslParallelExecutor" pool-size="50" />
<task:executor id="wldpParallelExecutor" pool-size="25" />
<task:executor id="lcParallelExecutor" pool-size="25" />
<task:executor id="irisParallelExecutor" pool-size="25" />
<int:gateway id="dslServiceFacade" service-interface="com.mycompany.tss.ls.dsl.gateway.IDSLServiceFacade"
default-request-channel="inputChannel" default-reply-channel="outputChannel" error-channel="gatewayErrorChannel" async-executor="dslParallelExecutor">
<int:method name="invoke" request-channel="inputChannel" request-timeout="5000" reply-timeout="3000000"/>
</int:gateway>
<int:service-activator input-channel="inputChannel"
output-channel="dslFlowInitiatorOutputChannel" ref="dslFlowInitiatorService"
method="invoke" id="dslFlowInitiator" />
<bean id="dslFlowInitiatorService" class="com.mycompany.tss.ls.dsl.service.DSLFlowInitiatorService" />
<int:splitter id="systemSplitter" input-channel="dslFlowInitiatorOutputChannel" method="split"
output-channel="routingChannel" ref="systemMessageSplitter">
</int:splitter>
<bean id="systemMessageSplitter" class="com.mycompany.tss.ls.dsl.splitter.SystemMessageSplitter"/>
<int:router id="systemRouter" input-channel="routingChannel" default-output-channel="nullChannel"
expression="headers.get('systemId')">
<int:mapping value="WLDP" channel="wldpInputChannel" />
<int:mapping value="LC" channel="lcInputChannel" />
<int:mapping value="IRIS" channel="irisInputChannel" />
</int:router>
<int:aggregator id="dslResponseAggregator" input-channel="aggregateDSLResponseChannel" output-channel="aggregateDSLOutputChannel"
message-store="dslResponseMessageStore" correlation-strategy-expression="headers['requestId']"
send-partial-result-on-expiry="true">
</int:aggregator>
<int:service-activator input-channel="aggregateDSLOutputChannel"
output-channel="outputChannel" ref="dslFlowEndService"
method="invoke" id="dslFlowEndActivator" />
<bean id="dslFlowEndService" class="com.mycompany.tss.ls.dsl.service.DSLFlowEndService" />
<bean id="dslResponseMessageStore" class="org.springframework.integration.store.SimpleMessageStore" />
<bean id="dslResponseMessageStoreReaper" class="org.springframework.integration.store.MessageGroupStoreReaper">
<property name="messageGroupStore" ref="dslResponseMessageStore" />
<property name="timeout" value="4000" />
</bean>
<task:scheduled-tasks>
<task:scheduled ref="dslResponseMessageStoreReaper" method="run" fixed-rate="10000" />
</task:scheduled-tasks>
<int:wire-tap pattern="*Channel" order="3" channel="wiretap"/>
<int:message-history/>
<int:logging-channel-adapter id="wiretap" level="DEBUG"/>
<!-- Error handling Service Activator to log exceptions and send the response -->
<int:service-activator id="errorHandlingServiceActivator" input-channel="gatewayErrorChannel"
method="invoke" output-channel="aggregateDSLResponseChannel" ref="errorHandlingService">
</int:service-activator>
<!-- Error Handling Service class -->
<bean id="errorHandlingService" class="com.mycompany.tss.ls.dsl.service.ErrorHandlingService" />
<bean id="wldpErrorHandlingService" class="com.mycompany.tss.ls.dsl.service.ErrorHandlingService" />
<bean id="irisErrorHandlingService" class="com.mycompany.tss.ls.dsl.service.ErrorHandlingService" />
<int:channel id="wldpStartChannel"></int:channel>
<int:channel id="irisStartChannel"></int:channel>
<int:channel id="wldpErrorChannel"></int:channel>
<int:channel id="irisErrorChannel"></int:channel>
<int:channel id="wldpOutputChannel"></int:channel>
<int:channel id="irisOutputChannel"></int:channel>
<int:service-activator id="midFlowWLDPActivator" input-channel="wldpInputChannel"
ref="midFlowWLDPGateway" output-channel="aggregateDSLResponseChannel"/>
<int:service-activator id="midFlowIRISActivator" input-channel="irisInputChannel"
ref="midFlowIRISGateway" output-channel="aggregateDSLResponseChannel"/>
<int:gateway id="midFlowWLDPGateway" default-request-channel="wldpStartChannel"
service-interface="com.mycompany.tss.ls.dsl.gateway.IDSLWLDPFacade" error-channel="wldpErrorChannel"
/>
<int:gateway id="midFlowIRISGateway" default-request-channel="irisStartChannel"
service-interface="com.mycompany.tss.ls.dsl.gateway.IDSLIRISFacade" error-channel="irisErrorChannel"
/>
<int:service-activator id="errorHandlingWLDPServiceActivator" input-channel="wldpErrorChannel"
method="invoke" ref="wldpErrorHandlingService">
</int:service-activator>
<int:service-activator id="errorHandlingIRISServiceActivator" input-channel="irisErrorChannel"
method="invoke" ref="irisErrorHandlingService">
</int:service-activator>
<!-- Responsible for closing all the activities related to WLDP before sending response -->
<int:service-activator id="wldpFlowEndServiceActivator" input-channel="wldpStartChannel"
method="invoke" ref="wldpFlowEndService">
</int:service-activator>
<bean id="wldpFlowEndService" class="com.mycompany.tss.ls.dsl.service.wldp.WLDPFlowEndService" />
<!-- Responsible for closing all the activities related to IRIS before sending response -->
<int:service-activator id="irisFlowEndServiceActivator" input-channel="irisStartChannel"
method="invoke">
</int:service-activator>
<bean id="irisFlowEndService" class="com.mycompany.tss.ls.dsl.service.iris.IrisFlowEndService" />
ErrorHandlingService:
公共类ErrorHandlingService {
Logger logger = LoggerFactory.getLogger(ErrorHandlingService.class);
public Message<DSLResponseVO> invoke(Message<?> requestMessage) {
Object exception = requestMessage.getPayload();
if(exception instanceof MessagingException){
DSLResponseVO responseVO = new DSLResponseVO();
logger.error("Exception has occurred: {}", ((MessagingException)exception).getMessage());
logger.error("Exception Stacktrace is: ", exception);
responseVO.setRequestId((String)((MessagingException)exception).getFailedMessage().getHeaders().get("requestId"));
responseVO.setSystemId((String)((MessagingException)exception).getFailedMessage().getHeaders().get("systemId"));
responseVO.setErrorCode(DSLErrorConstants.FAILURE_CODE);
responseVO.setErrorMessage(DSLErrorConstants.FAILURE_DESC);
Message<DSLResponseVO> failedMessage = MessageBuilder.withPayload(responseVO)
//.copyHeadersIfAbsent(((MessagingException)exception).getFailedMessage().getHeaders())
.setHeaderIfAbsent("requestId", (String)((MessagingException)exception).getFailedMessage().getHeaders().get("requestId"))
.setHeaderIfAbsent("systemId", (String)((MessagingException)exception).getFailedMessage().getHeaders().get("systemId"))
.setHeaderIfAbsent(MessageHeaders.SEQUENCE_NUMBER, (Integer)((MessagingException)exception).getFailedMessage().getHeaders().get(MessageHeaders.SEQUENCE_NUMBER))
.setHeaderIfAbsent(MessageHeaders.SEQUENCE_SIZE, (Integer)((MessagingException)exception).getFailedMessage().getHeaders().get(MessageHeaders.SEQUENCE_SIZE))
.setHeaderIfAbsent(MessageHeaders.REPLY_CHANNEL, ((MessagingException)exception).getFailedMessage().getHeaders().get(MessageHeaders.REPLY_CHANNEL))
.build();
return failedMessage;
}
return null;
}
}
答案 0 :(得分:0)
您无法向网关发送多个回复;您需要将结果(或失败)聚合到单个回复消息中。
每个子流都需要将结果或错误发送到聚合器。
每个子流都需要一个错误流。如果使用队列通道而不是执行程序通道,则可以在轮询器上放置错误通道。
使用执行程序通道时,您需要一个中流网关来添加错误流(引用<gateway/>
的服务激活器)。