簡體   English   中英

Spring 集成多隊列消費者

[英]Spring Integration multiple queue consumers

作為Spring integration MessageQueue without polling的結果,我有一個輪詢器使用自定義 TaskScheduler 立即使用隊列中的消息:

ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("resultProcessor-");

IntegrationFlows
  .from("inbound")
  .channel(MessageChannels.priority().get())
  .bridge(bridge -> bridge
    .taskScheduler(taskScheduler)
    .poller(Pollers.fixedDelay(0).receiveTimeout(Long.MAX_VALUE)))
  .fixedSubscriberChannel()
  .route(inboundRouter())
  .get()

現在我想讓多個線程同時使用,所以我嘗試了:

ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("resultProcessor-");
scheduler.setPoolSize(4);

但是,由於在AbstractPollingEndpoint中任務調度器調度了一個同步輪詢器(這有點復雜),因此只創建了 1 個線程。 如果我將 TaskExecutor 設置為SyncTaskExecutor (默認)以外的任何值,我就會遇到大量計划任務(請參閱Spring integration MessageQueue without polling )。

如何在 Spring 集成中同時從隊列中消費? 這看起來很基本,但我找不到解決方案。

我可以使用ExecutorChannel而不是隊列,但是,(AFAIK) 然后我失去了隊列功能,如優先級、隊列大小和我所依賴的指標。

請參閱PollerSpec.taskExecutor()

/**
 * Specify an {@link Executor} to perform the {@code pollingTask}.
 * @param taskExecutor the {@link Executor} to use.
 * @return the spec.
 */
public PollerSpec taskExecutor(Executor taskExecutor) {

這樣,在根據您的taskSchedulerdelay定期安排任務后,真正的任務是在提供的執行程序的線程上執行的。 默認情況下,它確實在調度程序的線程上執行任務。

更新

我不確定這是否滿足您的要求,但這是保持隊列邏輯和處理並行處理的唯一方法:

 .bridge(bridge -> bridge
    .taskScheduler(taskScheduler)
    .poller(Pollers.fixedDelay(0).receiveTimeout(Long.MAX_VALUE)))
 .channel(channels -> channel.executor(threadPoolExecutor()))   
 .fixedSubscriberChannel()

我能夠像這樣解決它:

  • 執行輪詢的單線程任務調度程序
  • 具有同步隊列的線程池執行器

這樣,任務調度程序可以為每個執行程序分配 1 個任務,並在沒有執行程序空閑時阻塞,從而不會耗盡源隊列或垃圾任務。

  @Bean
  public IntegrationFlow extractTaskResultFlow() {
    return IntegrationFlows
      .from(ChannelNames.TASK_RESULT_QUEUE)
      .bridge(bridge -> bridge
        .taskScheduler(taskResultTaskScheduler())
        .poller(Pollers
          .fixedDelay(0)
          .taskExecutor(taskResultExecutor())
          .receiveTimeout(Long.MAX_VALUE)))
      .handle(resultProcessor)
      .channel(ChannelNames.TASK_FINALIZER_CHANNEL)
      .get();
  }

  @Bean
  public TaskExecutor taskResultExecutor() {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(
      1, // corePoolSize
      8, // maximumPoolSize
      1L, // keepAliveTime
      TimeUnit.MINUTES,
      new SynchronousQueue<>(),
      new CustomizableThreadFactory("resultProcessor-")
    );
    executor.setRejectedExecutionHandler(new CallerBlocksPolicy(Long.MAX_VALUE));
    return new ErrorHandlingTaskExecutor(executor, errorHandler);
  }

  @Bean
  public TaskScheduler taskResultTaskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setThreadNamePrefix("resultPoller-");
    return scheduler;
  }

(最初的例子是從鏈接問題中復制的,這個現在類似於我的實際解決方案)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM