繁体   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