Spring Integration中使用发布 - 订阅进行的限时聚合

时间:2015-03-11 20:01:43

标签: spring-integration

我正在尝试使用Spring与DSL和lambda实现以下内容:

收到消息后,将其发送给N个消费者(通过publish-subscribe)。等待有限的时间并返回在该时间间隔内从消费者(<= N)到达的所有结果。

这是我到目前为止的示例配置:

@Configuration
@EnableIntegration
@IntegrationComponentScan
@ComponentScan
public class ExampleConfiguration {

    @Bean(name = PollerMetadata.DEFAULT_POLLER)
    public PollerMetadata poller() {
        return Pollers.fixedRate(1000).maxMessagesPerPoll(1).get();
    }

    @Bean
    public MessageChannel publishSubscribeChannel() {
        return MessageChannels.publishSubscribe(splitterExecutorService()).applySequence(true).get();
    }

    @Bean
    public ThreadPoolTaskExecutor splitterExecutorService() {
        final ThreadPoolTaskExecutor executorService = new ThreadPoolTaskExecutor();

        executorService.setCorePoolSize(3);
        executorService.setMaxPoolSize(10);

        return executorService;
    }

    @Bean
    public DirectChannel errorChannel() {
        return new DirectChannel();
    }

    @Bean
    public DirectChannel requestChannel() {
        return new DirectChannel();
    }

    @Bean
    public DirectChannel channel1() {
        return new DirectChannel();
    }

    @Bean
    public DirectChannel channel2() {
        return new DirectChannel();
    }

    @Bean
    public DirectChannel collectorChannel() {
        return new DirectChannel();
    }

    @Bean
    public TransformerChannel1 transformerChannel1() {
        return new TransformerChannel1();
    }

    @Bean
    public TransformerChannel2 transformerChannel2() {
        return new TransformerChannel2();
    }

    @Bean
    public IntegrationFlow errorFlow() {
        return IntegrationFlows.from(errorChannel())
                .handle(m -> System.err.println("[" + Thread.currentThread().getName() + "] " + m.getPayload()))
                .get();
    }

    @Bean
    public IntegrationFlow channel1Flow() {
        return IntegrationFlows.from(publishSubscribeChannel())
                .transform("1: "::concat)
                .transform(transformerChannel1())
                .channel(collectorChannel())
                .get();
    }

    @Bean
    public IntegrationFlow channel2Flow() {
        return IntegrationFlows.from(publishSubscribeChannel())
                .transform("2: "::concat)
                .transform(transformerChannel2())
                .channel(collectorChannel())
                .get();
    }

    @Bean
    public IntegrationFlow splitterFlow() {
        return IntegrationFlows.from(requestChannel())
                .channel(publishSubscribeChannel())
                .get();
    }

    @Bean
    public IntegrationFlow collectorFlow() {
        return IntegrationFlows.from(collectorChannel())
                .resequence(r -> r.releasePartialSequences(true),
                        null)
                .aggregate(a ->
                        a.sendPartialResultOnExpiry(true)
                                .groupTimeout(500)
                        , null)
                .get();
    }

}

TransformerChannel1TransformerChannel2是示例消费者,只是在睡眠时实施,以模拟延迟。

消息流是:

 splitterFlow -> channel1Flow \
              -> channel2Flow / -> collectorFlow

一切似乎都按预期工作,但我看到警告如:

  

收到回复邮件但收到的帖子已收到回复

这是预期的,因为返回了部分结果。

问题:

  • 总的来说,这是一个好方法吗?
  • 优雅地服务或丢弃这些延迟消息的正确方法是什么?
  • 如何处理异常?理想情况下,我想将它们发送到errorChannel,但我不确定在何处指定它。

1 个答案:

答案 0 :(得分:0)

是的,解决方案看起来不错。我想它适合Scatter-Gather模式。从版本4.1开始提供实现。

从另一方面来看,aggregator还有更多选项,因为该版本也是expire-groups-upon-timeout,默认情况下聚合器为true。使用此选项false,您将能够实现丢弃所有这些延迟消息的要求。不幸的是DSL并不支持yet。因此,即使您将项目升级为使用Spring Integration 4.1,它也无法提供帮助。

接收到的那些&#34;回复消息的另一个选项但是接收线程已经收到回复&#34;在spring.integraton.messagingTemplate.throwExceptionOnLateReply = true选项中,使用jar中spring.integration.properties内的META-INF文件。

无论如何,我认为Scatter-Gather是用例的最佳解决方案。 您可以在JavaConfig中找到here如何配置它。

<强>更新

  

异常和错误频道怎么样?

由于您已与throwExceptionOnLateReply达成交易,我猜您通过requestChannel@MessagingGateway发送消息。最后一个有errorChannel选项。另一方面,PublishSubscribeChannelerrorHandler选项,您可以MessagePublishingErrorHandler使用errorChannel作为默认选项。

顺便说一句,不要忘记框架为errorChannel提供endpoint bean和LoggingHandlererrorChannel。所以,请考虑,如果你真的需要覆盖那些东西。默认PublishSubscribeChannel为{{1}},因此您只需添加自己的订阅者即可。