[英]Spring Integration - Priority aggregator
我有以下应用要求:
types
属性(具有预先给定的类型时间映射)和基于现有时间消息已在队列中等待( old
属性) 正如您在图像中看到的一个用例:三条消息已经聚合并等待下一秒发布(因为当前速率为1msg/sec
),但就在那时, MSG
以id:10
到达,它更新了AGGREGATED 2
,使其成为优先级的第一条消息。 所以在下一个滴答声中,我们没有释放AGGREGATED 3
,而是释放AGGREGATED 2
,因为它现在具有更高的优先级。
现在,问题是 - 我可以为此使用 Spring 集成聚合器,因为我不知道它是否支持聚合期间的消息优先级? 我知道groupTimeout
,但那只是调整单个消息组 - 不改变其他组的优先级。 是否可以使用MessageGroupStoreReaper
在新的 MSG 到达时按优先级调整所有其他聚合消息?
更新
我做了一些这样的实现——现在看起来还可以——它在消息到达时聚合消息,比较器通过我的自定义逻辑对消息进行排序。
您认为这可能存在一些问题(并发等)吗? 我可以在日志中看到,轮询器在某些情况下被多次调用。 这是正常的吗?
2021-01-18 13:52:05.277 INFO 16080 --- [ scheduling-1] ggregatorConfig$PriorityAggregatingQueue : POLL
2021-01-18 13:52:05.277 INFO 16080 --- [ scheduling-1] ggregatorConfig$PriorityAggregatingQueue : POLL
2021-01-18 13:52:05.277 INFO 16080 --- [ scheduling-1] ggregatorConfig$PriorityAggregatingQueue : POLL
2021-01-18 13:52:05.277 INFO 16080 --- [ scheduling-1] ggregatorConfig$PriorityAggregatingQueue : POLL
另外,这个注释的doit
方法是在运行时增加最大轮询消息数的正确方法吗?
@Bean
public MessageChannel aggregatingChannel(){
return new QueueChannel(new PriorityAggregatingQueue<>((m1, m2) -> {//aggr here},
Comparator.comparingInt(x -> x),
(m) -> {
ExampleDTO d = (ExampleDTO) m.getPayload();
return d.getId();
}
));
}
class PriorityAggregatingQueue<K> extends AbstractQueue<Message<?>> {
private final Log logger = LogFactory.getLog(getClass());
private final BiFunction<Message<?>, Message<?>, Message<?>> accumulator;
private final Function<Message<?>, K> keyExtractor;
private final NavigableMap<K, Message<?>> keyToAggregatedMessage;
public PriorityAggregatingQueue(BiFunction<Message<?>, Message<?>, Message<?>> accumulator,
Comparator<? super K> comparator,
Function<Message<?>, K> keyExtractor) {
this.accumulator = accumulator;
this.keyExtractor = keyExtractor;
keyToAggregatedMessage = new ConcurrentSkipListMap<>(comparator);
}
@Override
public Iterator<Message<?>> iterator() {
return keyToAggregatedMessage.values().iterator();
}
@Override
public int size() {
return keyToAggregatedMessage.size();
}
@Override
public boolean offer(Message<?> m) {
logger.info("OFFER");
return keyToAggregatedMessage.compute(keyExtractor.apply(m), (k,old) -> accumulator.apply(old, m)) != null;
}
@Override
public Message<?> poll() {
logger.info("POLL");
Map.Entry<K, Message<?>> m = keyToAggregatedMessage.pollLastEntry();
return m != null ? m.getValue() : null;
}
@Override
public Message<?> peek() {
Map.Entry<K, Message<?>> m = keyToAggregatedMessage.lastEntry();
return m!= null ? m.getValue() : null;
}
}
// @Scheduled(fixedDelay = 10*1000)
// public void doit(){
// System.out.println("INCREASE POLL");
// pollerMetadata().setMaxMessagesPerPoll(pollerMetadata().getMaxMessagesPerPoll() * 2);
// }
@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata pollerMetadata(){
PollerMetadata metadata = new PollerMetadata();
metadata.setTrigger(new DynamicPeriodicTrigger(Duration.ofSeconds(30)));
metadata.setMaxMessagesPerPoll(1);
return metadata;
}
@Bean
public IntegrationFlow aggregatingFlow(
AmqpInboundChannelAdapter aggregatorInboundChannel,
AmqpOutboundEndpoint aggregatorOutboundChannel,
MessageChannel wtChannel,
MessageChannel aggregatingChannel,
PollerMetadata pollerMetadata
) {
return IntegrationFlows.from(aggregatorInboundChannel)
.wireTap(wtChannel)
.channel(aggregatingChannel)
.handle(aggregatorOutboundChannel)
.get();
}
好吧,如果有一条新消息需要组完成,它会到达聚合器,那么这样的组会立即释放(如果您的ReleaseStrategy
这么说的话)。 超时组的 rest 将继续等待调度。
可能会想出智能算法来依靠MessageGroupStoreReaper
的单个公共调度来决定我们是否需要释放该部分组或只是丢弃它。 再说一遍: ReleaseStrategy
应该给我们一个发布与否的线索,即使是部分发布。 当丢弃发生并且我们希望将这些消息保留在聚合器中时,我们需要在延迟一段时间后将它们重新发送回聚合器。 过期后,组从存储中删除,这发生在我们已经发送到丢弃通道时,所以最好延迟它们并让聚合器清理这些组,这样延迟后我们可以安全地将它们发送回作为新组的一部分的新到期期限的聚合器。
您可能还可以在发布普通组后迭代存储中的所有消息,以调整其标题中的一些时间键以用于下一个到期时间。
我知道这很困难,但实际上没有任何开箱即用的解决方案,因为它的设计目的不是为了影响我们刚刚处理的其他群体......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.