spring integration : response message not sent to client from error-channel

旧城冷巷雨未停 提交于 2020-01-24 13:03:52

问题


I've the understanding that Spring Integration (SI) will wrap any exception (under the SI domain) to a MessageException instance and place it on the "error-channel".

Following are few snippets from my spring config file :

<int:channel-interceptor pattern="ersServiceReqRcvPostValidationChannel,ersServiceResRcvPostValidationChannel" order="1">
    <bean class="com.bnym.ecs.report.service.orchestration.interceptors.MsgJSONSyntaxValidationInterceptor"/>
</int:channel-interceptor>

<int:channel-interceptor pattern="ersServiceReqRcvPostValidationChannel,ersServiceResRcvPostValidationChannel" order="2">
    <bean class="com.bnym.ecs.report.service.orchestration.interceptors.MsgMetaDataValidationInterceptor"/>
</int:channel-interceptor>

<!--  Gateways -->
<int:gateway id="ersServiceReqRcvGateway"
    service-interface="com.bnym.ecs.report.service.orchestration.gateway.ERSOrchestrationSvcReqGateway"
    error-channel="reqRcvExceptionHandlerChannel">
    <int:method name="processRequest" request-channel="ersServiceReqRcvPostValidationChannel" />
</int:gateway>

<!--  Chain to handle all incoming request *after* doing all validations -->
<int:chain input-channel="ersServiceReqRcvPostValidationChannel">
    <int:service-activator ref="msgReqAuditDetailDAOIntegrator" method="persist" />
    <!--  Router -->
    <int:router ref="ersServiceReqRcvRouter" />
</int:chain>

<!--  6) Pass the message through ERS svc to Exec svc ADH chain - Chain2 -->
<int:chain input-channel="ersSvc2execSvcQMRChannel" output-channel="ersServiceResRcvPostValidationChannel">
    <int:transformer ref="json2ObjTransformer" method="transformToERSOrchestrationSvcReq" />
    <int:service-activator ref="executionSvcReqMsgBuilder" method="getRptExecutionSvcReqForDataEngine" />
    <int:transformer ref="obj2JsonTransformer" method="transformFromRptExecutionSvcReqForDataEngine" />
    <int:service-activator ref="msgReqAuditDAOIntegrator" method="persist" />
    <int:service-activator ref="msgReqAuditDetailDAOIntegrator" method="persist" />
    <int:service-activator ref="executionSvcRESTStub" method="executeReportJSON" />
</int:chain>

<int:chain input-channel="reqRcvExceptionHandlerChannel">
    <int:transformer ref="exceptionTransformer" method="handleError"/>
</int:chain>

The client makes a REST call to my implementation class which inturn places the received request on the Gateway defined in above spring config file

@Path("/reportExecutor")
public class ERSOrchestrationServiceImpl {

    @Autowired
    private ReportInstanceDAO reportInstanceDAO;

    private static final ERSOrchestrationSvcDiagnosticLogger _logger = 
    ERSOrchestrationSvcDiagnosticLogger.getInstance(ERSOrchestrationServiceImpl.class);

    @Context
    HttpServletRequest request;
    @Context
    HttpServletResponse response;

    @POST
    @Path("/executeOnlineReport")
    @Produces({MediaType.APPLICATION_JSON})
    public String executeOnlineReport(String jsonRequest) {

        ApplicationContext appCtx = SpringApplicationContextUtil.getApplicationContext();

        ERSOrchestrationSvcReqGateway ersOrchestrationSvcReqGateway = 
            (ERSOrchestrationSvcReqGateway) appCtx.getBean("ersServiceReqRcvGateway");

        Message<String> inputMsg = MessageBuilder.withPayload(jsonRequest)
                                                 .setHeader(ERSServiceConstants.KEY_MSG_CORRELATION_ID, correlationId)
                                                 .setHeader(ERSServiceConstants.KEY_MSG_REPORT_INSTANCE_ID, reportInstanceId)
                                                 .build();

        Message<String> returnMsg = ersOrchestrationSvcReqGateway.processRequest(inputMsg);
        return returnMsg.getPayload();

    }

As mentioned in above spring config file, the error-channel is read by a Transformer that creates a valid failed response message for the client and returns the message.

public class ErrorMessageUnwrapTransformer {

    @Autowired
    private Gson gsonUtil;
    @Autowired
    private ReportInstanceDAO reportInstanceDAO;
    @Autowired
    private ERSOrchestrationSvcFailedResMsgBuilder executionSvcFailedMsgBuilder;

    private static final ERSOrchestrationSvcDiagnosticLogger _log = 
    ERSOrchestrationSvcDiagnosticLogger.getInstance(ErrorMessageUnwrapTransformer.class); 

    @Transformer
    public Message<?> handleError(Message<?> message) {
        try{
            failedMsg = ((MessagingException) message.getPayload()).getFailedMessage();

            //some code logic to build a valid failed response message goes here
            Message<?> failedResponseMsg = executionSvcFailedMsgBuilder.getERSOrcSvcFailedResMsg(failedMsg );

            return failedResponseMsg;
        }

All seems to work fine when I get an exception, i.e., the exception is wrapped as MessagingException, put on the error-channel, the Transformer is able to read the channel, get failedMessage out of it, able to create a valid failed response message and return it.

However, the only issue I get is the call does not go back to the caller. In other words, the handle does not go back to the following code that had initiated the processing flow:

Message<String> returnMsg = ersOrchestrationSvcReqGateway.processRequest(inputMsg);   

Can someone pls let me know why is the message returned by error-channel-read-Transformer not returning back to the class that invoked the Gateway method ?


回答1:


Your problem here that you return the entire Message<?> from the transformer. This one is a component which doesn't care about headers, when the returned object is Message<?> already. You should worry about them on your own, like copy all headers from the failedMsg to your own failedResponseMsg.

Why is that so important?

Since you use request/reply gateway you are expecting for the return on that method invocation, something on the background ensure that for you. And it is a classical replyChannel algorithm.

Any AbstractReplyProducingMessageHandler sends its result to the replyChannel, if you don't have an outputChannel configured, like your reqRcvExceptionHandlerChannel <chain> here.

With other components we can rely on the copy-header-from-request function, but not here with the <transformer>.

From other side ErrorMessage may be created in some context where we don't have headers, but we exactly may have the failedMessage in the MessagingException for which the ErrorMessage has been caused. So, we have to ensure headers from that failedMessage.

Hope I am clear.



来源:https://stackoverflow.com/questions/16894292/spring-integration-response-message-not-sent-to-client-from-error-channel

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!