Apache camel 带激发/遗忘和超时的拆分器/聚合器

Apache camel 带激发/遗忘和超时的拆分器/聚合器,apache-camel,Apache Camel,我们有一个拆分进程,它将消息推送到不同的队列。还有另一个进程收集和聚合这些消息以供进一步处理 我们希望在拆分和聚合之间有一个超时。 IIUC聚合超时从第一条消息开始,并在每个聚合消息之后重置(它是基于时间间隔的,而不是针对完整消息) 解决这个问题的最佳解决方案是什么 编辑 这是我能想出的最好的办法,虽然有点不对劲。首先,将时间戳保存为消息头,并将其发布到带有正文的队列中: from("somewhere") .split(body()) .process(e -> e.ge

我们有一个拆分进程,它将消息推送到不同的队列。还有另一个进程收集和聚合这些消息以供进一步处理

我们希望在拆分和聚合之间有一个超时。 IIUC聚合超时从第一条消息开始,并在每个聚合消息之后重置(它是基于时间间隔的,而不是针对完整消息)

解决这个问题的最佳解决方案是什么

编辑

这是我能想出的最好的办法,虽然有点不对劲。首先,将时间戳保存为消息头,并将其发布到带有正文的队列中:

from("somewhere")
    .split(body())
    .process(e -> e.getIn().setHeader("aggregation_timeout", 
        ZonedDateTime.now().plusSeconds(COMPLETION_TIMEOUT)))
    .to("aggregation-route-uri");
然后,在消费和聚合时,使用自定义聚合策略保存当前组中第一条消息的
聚合超时
,然后使用读取该值的
完成谓词
检查超时是否已过期(或者,如果以保持邮件顺序不变的方式进行聚合,则可以从第一封邮件中读取标题)。在两封邮件间隔较长的情况下,使用短的
completionTimeout
作为保护措施:

from("aggregation-route-uri")
    .aggregate(bySomething())
    .aggregationStrategy((oldExchange, newExchange) -> {
      // read aggregation_timeout header from first message 
      // and set it as property in grouped exchange
      // perform aggregation
    })
    .completionTimeout(1000) // intentionally low value, here as a safeguard
    .completionPredicate(e -> {
      // complete once the timeout has been reached
      return e.getProperty("aggregation_timeout", ZonedDateTime.class)
              .isAfter(ZonedDateTime.now());
    })
    .process(e -> // do something with aggregates);
编辑

下面是我能想到的最好的方法,尽管这有点麻烦。首先,您将时间戳保存为消息头,并将其与正文一起发布到队列:

from("somewhere")
    .split(body())
    .process(e -> e.getIn().setHeader("aggregation_timeout", 
        ZonedDateTime.now().plusSeconds(COMPLETION_TIMEOUT)))
    .to("aggregation-route-uri");
然后,在消费和聚合时,使用自定义聚合策略保存当前组中第一条消息的
聚合超时
,然后使用读取该值的
完成谓词
检查超时是否已过期(或者,如果以保持邮件顺序不变的方式进行聚合,则可以从第一封邮件中读取标题)。在两封邮件间隔较长的情况下,使用短的
completionTimeout
作为保护措施:

from("aggregation-route-uri")
    .aggregate(bySomething())
    .aggregationStrategy((oldExchange, newExchange) -> {
      // read aggregation_timeout header from first message 
      // and set it as property in grouped exchange
      // perform aggregation
    })
    .completionTimeout(1000) // intentionally low value, here as a safeguard
    .completionPredicate(e -> {
      // complete once the timeout has been reached
      return e.getProperty("aggregation_timeout", ZonedDateTime.class)
              .isAfter(ZonedDateTime.now());
    })
    .process(e -> // do something with aggregates);


我忘了提到拆分器和聚合器都有自己的CamelContext,因为我们预期外部系统会有大量的消息和长时间运行的任务。聚合信息是持久化的。我认为建议的解决方案不适用于分离的CamelContext,对吧?我不明白为什么它不起作用,它与上下文无关如果一个消息包只包含一条消息,仍然会有问题。这样的消息也应该被处理(错误处理)当超时发生时。至少这确认了还没有现成的模式。completionTimeout不处理单一消息场景吗?如果捆绑包只包含一条消息,它将在一秒钟后聚合。拆分的消息将放在队列上,这取决于第三方处理该消息的速度以及回复我们的聚合器队列。如果这需要太多时间,messagebundle应该超时。我忘了提到拆分器和聚合器都有自己的上下文,因为我们预期外部系统会有大量的消息和长时间运行的任务。聚合信息会被持久化。我认为建议的解决方案在如果消息包只包含一条消息,那么问题仍然存在。这样的消息也应该被处理(错误处理)当超时发生时。至少这确认了还没有现成的模式。completionTimeout不处理单一消息场景吗?如果捆绑包只包含一条消息,它将在一秒钟后聚合。拆分的消息将放在队列上,这取决于第三方处理该消息的速度以及回复我们的聚合器队列。如果这需要太多时间,messagebundle应该超时。因此,您希望聚合器假设,如果自消息拆分后已过NNNN秒,则特定的聚合已完成?是否正确?是的,拆分和聚合“messagebundle”的总时间可能不会超过NNNN秒。哦,我当时完全误解了这个问题-我以为你想推迟聚合一段时间-我完全偏离了目标。我能想到的最接近的方法是使用
completionInterval
而不是
completionTimeout
,也许看看它是否可以与完成谓词;如果其他人在这段时间内没有弄明白,我将在明天尝试一下。我们一直在考虑向聚合器队列发送某种虚拟通知消息,该队列将开始计算超时。但是仍然存在使用每一条新消息重置超时的问题。因此,您希望聚合器假设某个特定的聚合已完成,如果自消息拆分后已过NNNN秒?是否正确?是,拆分和聚合“messagebundle”的总时间可能不会超过NNNN秒。哦,我当时完全误解了这个问题-我以为你想推迟聚合一段时间-我完全偏离了目标。我能想到的最接近的方法是使用
completionInterval
而不是
completionTimeout
,也许看看它是否可以与完成谓词;如果其他人在这段时间内没有弄明白,我明天会尝试一下。我们一直在考虑向聚合器队列发送某种虚拟通知消息,聚合器队列将开始计算超时。但是,仍然存在使用每一条新消息重置超时的问题。