Spring集成:如何在聚合器之后处理服务中的异常?

时间:2014-09-23 15:32:44

标签: spring-integration amqp

我有一个依赖于Spring Integration(4.0.4.RELEASE)和RabbitMQ的应用程序。我的流程如下:

消息通过进程放入队列(他们不期望任何答案): 网关 - >频道 - >的RabbitMQ

然后被另一个过程耗尽:

RabbitMQ --1--> inbound-channel-adapter A --2--> chain B --3--> aggregator C --4--> service-activator D --5--> final service-activator E

解释&上下文

具体问题是在我的应用程序中没有任何地方我使用分割器:聚合器C 只是等待足够的消息来到,或者超时到期,然后将批处理转发到服务D 。消息可能会在聚合器C 中停留相当长的时间,并且不应被视为在那里消费。只有在服务D 成功完成后才能使用它们。因此,我在入站通道适配器A 上使用MANUAL确认,服务E 负责确认批次。

自定义聚合器

通过重新定义聚合器,我解决了设置为AUTO时的确认问题。实际上,如果流中发生任何异步过程,则会立即确认消息(请参阅问题here)。因此,我切换到MANUAL确认并实现了这样的聚合器:

     <bean class="org.springframework.integration.config.ConsumerEndpointFactoryBean">
        <property name="inputChannel" ref="channel3"/>
        <property name="handler">
            <bean class="org.springframework.integration.aggregator.AggregatingMessageHandler">
                <constructor-arg name="processor">
                    <bean class="com.test.AMQPAggregator"/>
                </constructor-arg>
                <property name="correlationStrategy">
                    <bean class="com.test.AggregatorDefaultCorrelationStrategy" />
                </property>
                <property name="releaseStrategy">
                    <bean class="com.test.AggregatorMongoReleaseStrategy" />
                </property>
                <property name="messageStore" ref="messageStoreBean"/>
                <property name="expireGroupsUponCompletion" value="true"/>
                <property name="sendPartialResultOnExpiry" value="true"/>
                <property name="outputChannel" ref="channel4"/>
            </bean>
        </property>
    </bean>

    <bean id="messageStoreBean" class="org.springframework.integration.store.SimpleMessageStore"/>

    <bean id="messageStoreReaperBean" class="org.springframework.integration.store.MessageGroupStoreReaper">
        <property name="messageGroupStore" ref="messageStore" />
        <property name="timeout" value="${myapp.timeout}" />
    </bean>

    <task:scheduled-tasks>
        <task:scheduled ref="messageStoreReaperBean" method="run" fixed-rate="2000" />
    </task:scheduled-tasks>

我确实希望以不同的方式聚合标题,并保留所有 amqp_deliveryTag 的最高值,以便稍后在服务E 中进行多重协调(请参阅{{ 3}}线程)。到目前为止,这种方法效果很好,除了它比典型的聚合器命名空间(参见this旧Jira票证)更加冗长。

服务

我只是使用基本配置:

链-B

<int:chain input-channel="channel2" output-channel="channel3">
        <int:header-enricher>
            <int:error-channel ref="errorChannel" /> // Probably useless
        </int:header-enricher>
        <int:json-to-object-transformer/>
        <int:transformer    ref="serviceABean" 
                            method="doThis" />
        <int:transformer    ref="serviceBBean" 
                            method="doThat" />
    </int:chain>

服务-d

<int:service-activator  ref="serviceDBean"
                            method="doSomething"
                            input-channel="channel4"
                            output-channel="channel5" />

错误管理

由于我依赖MANUAL确认,我还需要手动拒绝消息,以防发生异常。我对入站通道适配器A

有以下定义
<int-amqp:inbound-channel-adapter   channel="channel2"
                                            queue-names="si.queue1"
                                            error-channel="errorChannel"
                                            mapped-request-headers="*"
                                            acknowledge-mode="MANUAL"
                                            prefetch-count="${properties.prefetch_count}"
                                            connection-factory="rabbitConnectionFactory"/>

我对 errorChannel 使用以下定义:

<int:chain input-channel="errorChannel">
            <int:transformer ref="errorUnwrapperBean" method="unwrap" />
            <int:service-activator ref="amqpAcknowledgerBean" method="rejectMessage" />
</int:chain>

ErrorUnwrapper基于this代码,整个异常检测和消息拒绝都有效,直到消息到达聚合器C

问题

如果在处理 service-activator D 中的邮件时出现异常,那么我会看到此异常,但 errorChannel 似乎没有收到任何消息,而我的< em> ErrorUnwrapper unwrap()方法未被调用。我抛出的 Exception(&#34; ahahah&#34;)时看到的定制堆栈跟踪如下:

2014-09-23 16:41:18,725 ERROR o.s.i.s.SimpleMessageStore:174: Exception in expiry callback
org.springframework.messaging.MessageHandlingException: java.lang.Exception: ahahaha
    at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:78)
    at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:71)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:170)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
(...)

Caused by: java.lang.Exception: ahahaha
    at com.myapp.ServiceD.doSomething(ServiceD.java:153)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
(...)

2014-09-23 16:41:18,733 ERROR o.s.s.s.TaskUtils$LoggingErrorHandler:95: Unexpected error occurred in scheduled task.
org.springframework.messaging.MessageHandlingException: java.lang.Exception: ahahaha
(...)

问题

如何告诉处理来自此类聚合器的邮件的服务将错误发布到 errorChannel ?我试图在标题中通过 header-richher 指定错误通道而没有运气。我使用默认的 errorChannel 定义,但我也尝试更改其名称并重新定义它。我在这里一无所知,即使我找到了thisthis,我也没有设法让它发挥作用。在此先感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

正如您在StackTrace中看到的那样,您的流程是从MessageGroupStoreReaper线程开始的,该线程是从默认的ThreadPoolTaskScheduler启动的。

因此,您必须为此提供自定义bean:

<bean id="scheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
    <property name="errorHandler">
        <bean class="org.springframework.integration.channel.MessagePublishingErrorHandler">
            <property name="defaultErrorChannel" ref="errorChannel"/>
        </bean>
    </property>
</bean>

<task:scheduled-tasks scheduler="scheduler">
    <task:scheduled ref="messageStoreReaperBean" method="run" fixed-rate="2000" />
</task:scheduled-tasks>

但是我看到error-channel上的<aggregator>带来的好处,我们真正从不同的分离线程获得了几个点,我们无法正常处理。