集成模式:如何同步从多个系统接收的处理消息

时间:2017-09-16 13:39:01

标签: java design-patterns apache-camel spring-integration integration-patterns

我正在构建一个系统,它将通过来自不同系统的消息代理(当前,JMS)接收消息。来自所有发件人系统的所有消息都有一个deviceId,并且在接收消息时没有命令。 例如,系统A可以发送带有deviceId = 1的消息,而系统b可以发送带有deviceId = 2的消息。

我的目标不是开始处理有关同一deviceId的消息,除非我从所有发送者获得具有相同deviceId的所有消息。

例如,如果我有3个系统A,B和C向我的系统发送消息:

System A sends messageA1 with deviceId=1
System B sends messageB1 with deviceId=1
System C sends messageC1 with deviceId=3
System C sends messageC2 with deviceId=1 <--- here I should start processing of messageA1, messageB1 and messageC2 because they are having the same deviceID 1.

在我的系统中使用一些同步机制,消息代理还是像spring-integration / apache camel这样的集成框架,是否可以解决这个问题?

3 个答案:

答案 0 :(得分:2)

使用聚合器(@Artem Bilan提到的)的类似解决方案也可以在Camel中使用自定义AggregationStrategy实现,并使用Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP属性控制聚合器完成。

以下可能是一个很好的起点。 (You can find the sample project with tests here

路线:

from("direct:start")
    .log(LoggingLevel.INFO, "Received ${headers.system}${headers.deviceId}")
    .aggregate(header("deviceId"), new SignalAggregationStrategy(3))
    .log(LoggingLevel.INFO, "Signaled body: ${body}")
    .to("direct:result");

SignalAggregationStrategy.java

public class SignalAggregationStrategy extends GroupedExchangeAggregationStrategy implements Predicate {

    private int numberOfSystems;

    public SignalAggregationStrategy(int numberOfSystems) {
        this.numberOfSystems = numberOfSystems;
    }

    @Override
    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
        Exchange exchange = super.aggregate(oldExchange, newExchange);

        List<Exchange> aggregatedExchanges = exchange.getProperty("CamelGroupedExchange", List.class);

        // Complete aggregation if we have "numberOfSystems" (currently 3) different messages (where "system" headers are different)
        // https://github.com/apache/camel/blob/master/camel-core/src/main/docs/eips/aggregate-eip.adoc#completing-current-group-decided-from-the-aggregationstrategy
        if (numberOfSystems == aggregatedExchanges.stream().map(e -> e.getIn().getHeader("system", String.class)).distinct().count()) {
            exchange.setProperty(Exchange.AGGREGATION_COMPLETE_CURRENT_GROUP, true);
        }

        return exchange;
    }

    @Override
    public boolean matches(Exchange exchange) {
        // make it infinite (4th bullet point @ https://github.com/apache/camel/blob/master/camel-core/src/main/docs/eips/aggregate-eip.adoc#about-completion)
        return false;
    }
}

希望它有所帮助!

答案 1 :(得分:1)

您可以使用缓存组件在Apache Camel中执行此操作。我认为有EHCache组件。

本质:

  1. 您收到一条消息,其中包含给定的设备IDId,例如deviceId1。
  2. 您在缓存中查找以查看已收到deviceId1的消息。
  3. 只要您还没有收到全部三个,就可以将当前系统/消息添加到缓存中。
  4. 一旦所有消息都存在,您就可以处理并清除缓存。
  5. 然后,您可以将每个传入消息路由到特定的基于deviceId的队列以进行临时存储。这可以是JMS,ActiveMQ或类似的东西。

答案 2 :(得分:1)

Spring Integration为这类任务提供了组件 - 在收集整个组之前不要发出。它的名字是Aggregator。您的deviceId绝对是correlationKeyreleaseStrategy实际上可能基于系统数量 - 在进行下一步之前您要等待多少deviceId1条消息。