[英]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.