Spring kafka 用spring kafka实现延迟消息处理

Spring kafka 用spring kafka实现延迟消息处理,spring-kafka,Spring Kafka,由于kafka没有对延迟消息可视性的隐式支持,我们必须手动实现它 我正在尝试使用下面的方法来实现它- 在发送消息时,在消息有效负载中添加delayUnseconds和eventTime字段 接收消息时,计算应处理消息的确切时间 根据上述值和现在,计算消费者必须等待的时间 如果timetobedayed为正值,则暂停container,等待持续时间并在同一线程上恢复容器 在resume调用之后,抛出一个异常,这将使SeektocurInterrorHandler重试消息处理。(如果未执行此操作,则

由于kafka没有对延迟消息可视性的隐式支持,我们必须手动实现它

我正在尝试使用下面的方法来实现它-

  • 在发送消息时,在消息有效负载中添加
    delayUnseconds
    eventTime
    字段
  • 接收消息时,计算应处理消息的确切时间
  • 根据上述值和现在,计算消费者必须等待的时间
  • 如果
    timetobedayed
    为正值,则暂停container,等待持续时间并在同一线程上恢复容器
  • 在resume调用之后,抛出一个异常,这将使SeektocurInterrorHandler重试消息处理。(如果未执行此操作,则消费者无法处理最后一条消息)
  • 这一切都可以正常工作,容器进入睡眠状态并根据上述逻辑恢复。但我有几个问题-

  • 我们是否需要在同一线程上使用和恢复容器
  • 是否有另一种方法来寻找当前偏移量(而不是像这里所做的那样使用STCEH)?所涉及的复杂性是什么
  • 使用ConcurrentListenerContaienrs时,上述实现是否会有任何问题
  • 是否有一种方法可以根据消费者记录有效负载计算STCEH中的退避?如果是,那么让这个kafkaConsumer保持活动状态的实现是否会对代理产生影响(比如延迟不超过max.poll.interval)
  • 最后,上面的实现中有哪些可能的缺点,这将使它成为一个不可行的选择

  • 谢谢

    如果从侦听器线程调用
    pauseThenResumeAfter()
    ,它将无效;在侦听器方法执行之前,容器实际上不会暂停

    您应该看看新的2.7功能

    您应该能够重用它的一些基础设施来实现您的需求

    public class DelayedMessage {
        
      String messageId;
      Instant eventTime;
      Long delayInSeconds;
    }
    
    private Instant getInstantWhenToBeProcessed() {
      return eventTime.plus(delayInSeconds, ChronoUnit.SECONDS);
    }
    
    public long getTimeToBeDelayedInMillis() {
      return Duration.between(Instant.now(), getInstantWhenToBeProcessed()).toMillis();
    }
    
    @Service
    public class KafkaManager {
      
      @Autowired
      private KafkaListenerEndpointRegistry registry;
      
      public void pauseThenResumeAfter(long delayInMillis) throws InterruptedException {
    
        this.pause();
    
        log.info("Sleeping current thread by: {}ms", delayInMillis);
        Thread.sleep(delayInMillis);
        log.info("Waking up the thread");
    
        this.resume();
    
        // Throw exception, so that SeekToCurrentErrorHandle does a seek and tries to re-process
        throw new IllegalArgumentException("Failed to process record, as they instantToProcess has not yet arrived. Will retry after backoff");
      }
    
      public void pause() {
        registry.getListenerContainers().forEach(MessageListenerContainer::pause);
      }
    
      public void resume() {
        registry.getListenerContainers().forEach(MessageListenerContainer::resume);
      }
    }