Java 如何为卡夫卡寻找带弹簧的时间戳偏移量

Java 如何为卡夫卡寻找带弹簧的时间戳偏移量,java,spring-boot,apache-kafka,timestamp,spring-kafka,Java,Spring Boot,Apache Kafka,Timestamp,Spring Kafka,我们使用SpringKafka来使用必须作为服务器发送事件(SSE)转发到前端的消息 当用户登录时,她应该看到自上次会话以来错过的所有事件 当前实现使用ConsumerSekCallback,如中所述 但是,该回调不支持底层KafkaConsumer()的offsetForTimes方法 所以我必须使用seektobegining和时间戳过滤器,当有很多消息时,这会导致问题 有没有其他方法只接收给定时间戳后的消息? 可能是一种直接使用消费者的安全方式?2.0引入了ConsumerAwareRe

我们使用SpringKafka来使用必须作为服务器发送事件(SSE)转发到前端的消息

当用户登录时,她应该看到自上次会话以来错过的所有事件

当前实现使用ConsumerSekCallback,如中所述

但是,该回调不支持底层KafkaConsumer()的offsetForTimes方法

所以我必须使用seektobegining和时间戳过滤器,当有很多消息时,这会导致问题

有没有其他方法只接收给定时间戳后的消息?
可能是一种直接使用消费者的安全方式?

2.0引入了
ConsumerAwareRebalanceListener
(当前版本为2.2.2)


请参阅以获取示例。

2.0引入了
ConsumerAwareRebalanceListener
(当前版本为2.2.2)


请参见示例。

正如Gary Russel在上文中指出的,ConsumerSekCallback是传统的,因此它是一个不可能的。。。我不会公开GitHub的问题

我终于实现了我的目标:

当一个用户登录时,她应该能看到她所看到的所有事件 自从上次治疗后,她就错过了

通过在ListenerContainerIdleEvent的EventListener中处理所有新订阅,其中使用者作为事件数据的一部分可用:

    @EventListener(condition = "event.listenerId.startsWith('qux-')")
    public void idleEventHandler(ListenerContainerIdleEvent event) {

        // find new subscriptions
        Collection<EventListenerSubscription> newSubscriptions = 
                subscriptions.stream().filter(s -> s.isNew())
                .collect(Collectors.toList());

        if (!newSubscriptions.isEmpty()) {

            // mark subscriptions a not new
            newSubscriptions.forEach(s -> s.setNew(false));

            // compute the oldest time stamp
            OptionalLong oldestTimeStamp = 
                    newSubscriptions.stream()
                    .mapToLong(s -> s.getLastTimeStamp())
                    .reduce(Long::min);

            if (oldestTimeStamp.isPresent()) {

                // seek on topic for oldest time stamp
                Map<TopicPartition, Long> timestampsToSearch = new HashMap<>();
                timestampsToSearch.put(new TopicPartition(eventTopic, 0),
                                       oldestTimeStamp.getAsLong());
                Consumer<?, ?> consumer = event.getConsumer();
                event.getConsumer().offsetsForTimes(timestampsToSearch).forEach((k, v) -> {
                    consumer.seek(k, v.offset());
                });
            }
        }
    }
@EventListener(condition=“event.listenerId.startsWith('qux-'))
public void idleEventHandler(ListenerContainerIdleEvent事件){
//查找新订阅
集合新闻订阅=
subscriptions.stream().filter(s->s.isNew())
.collect(Collectors.toList());
如果(!newSubscriptions.isEmpty()){
//将订阅标记为非新订阅
newSubscriptions.forEach(s->s.setNew(false));
//计算最早的时间戳
OptionalLong oldestTimeStamp=
newSubscriptions.stream()
.mapToLong(s->s.getLastTimeStamp())
.减少(长::分钟);
if(oldestTimeStamp.isPresent()){
//在主题上查找最早的时间戳
Map timestampsToSearch=newhashmap();
timestampsToSearch.put(新的主题分区(eventTopic,0),
oldestTimeStamp.getAsLong());
Consumer=event.getConsumer();
event.getConsumer().offsetsForTimes(timestamstosearch).forEach((k,v)->{
consumer.seek(k,v.offset());
});
}
}
}
我确定所有新订阅中最早的时间戳,将这些订阅标记为非新订阅,并使用使用者在主题上查找最早的时间戳

为了获取容器空闲事件,必须在容器属性中配置空闲时间间隔,如下所述

KafkaListener将负责将旧事件发送给(以前的新)订阅者:

    @KafkaListener(id = "qux", topics = { "${app.event.topic}" }, errorHandler = "kafkaListenerErrorHandler")
    public void receive(@Payload Event event, @Headers MessageHeaders headers) throws JsonProcessingException {

        // collect the subscribers not marked as new
        Collection<EventListenerSubscription> oldSubscriptions = 
                subscriptions.stream().filter(s -> !s.isNew())
                .collect(Collectors.toList());

        for (EventListenerSubscription s : oldSubscriptions) {
            if (s.getLastTimeStamp() < timestamp) {
                s.addMessage(event, timestamp);
            }
        }
    }
@KafkaListener(id=“qux”,topics={“${app.event.topic}}”,errorHandler=“kafkaListenerErrorHandler”)
public void receive(@Payload Event Event,@Headers MessageHeaders)抛出JsonProcessingException{
//收集未标记为新的订阅服务器
集合订阅=
subscriptions.stream().filter(s->!s.isNew())
.collect(Collectors.toList());
对于(EventListener订阅:旧订阅){
if(s.getLastTimeStamp()
正如Gary Russel在上面指出的那样,ConsumerSekCallback是传统的,所以它是不可能的。。。我不会公开GitHub的问题

我终于实现了我的目标:

当一个用户登录时,她应该能看到她所看到的所有事件 自从上次治疗后,她就错过了

通过在ListenerContainerIdleEvent的EventListener中处理所有新订阅,其中使用者作为事件数据的一部分可用:

    @EventListener(condition = "event.listenerId.startsWith('qux-')")
    public void idleEventHandler(ListenerContainerIdleEvent event) {

        // find new subscriptions
        Collection<EventListenerSubscription> newSubscriptions = 
                subscriptions.stream().filter(s -> s.isNew())
                .collect(Collectors.toList());

        if (!newSubscriptions.isEmpty()) {

            // mark subscriptions a not new
            newSubscriptions.forEach(s -> s.setNew(false));

            // compute the oldest time stamp
            OptionalLong oldestTimeStamp = 
                    newSubscriptions.stream()
                    .mapToLong(s -> s.getLastTimeStamp())
                    .reduce(Long::min);

            if (oldestTimeStamp.isPresent()) {

                // seek on topic for oldest time stamp
                Map<TopicPartition, Long> timestampsToSearch = new HashMap<>();
                timestampsToSearch.put(new TopicPartition(eventTopic, 0),
                                       oldestTimeStamp.getAsLong());
                Consumer<?, ?> consumer = event.getConsumer();
                event.getConsumer().offsetsForTimes(timestampsToSearch).forEach((k, v) -> {
                    consumer.seek(k, v.offset());
                });
            }
        }
    }
@EventListener(condition=“event.listenerId.startsWith('qux-'))
public void idleEventHandler(ListenerContainerIdleEvent事件){
//查找新订阅
集合新闻订阅=
subscriptions.stream().filter(s->s.isNew())
.collect(Collectors.toList());
如果(!newSubscriptions.isEmpty()){
//将订阅标记为非新订阅
newSubscriptions.forEach(s->s.setNew(false));
//计算最早的时间戳
OptionalLong oldestTimeStamp=
newSubscriptions.stream()
.mapToLong(s->s.getLastTimeStamp())
.减少(长::分钟);
if(oldestTimeStamp.isPresent()){
//在主题上查找最早的时间戳
Map timestampsToSearch=newhashmap();
timestampsToSearch.put(新的主题分区(eventTopic,0),
oldestTimeStamp.getAsLong());
Consumer=event.getConsumer();
event.getConsumer().offsetsForTimes(timestamstosearch).forEach((k,v)->{
consumer.seek(k,v.offset());
});
}
}
}
我确定所有新订阅中最早的时间戳,将这些订阅标记为非新订阅,并使用使用者在主题上查找最早的时间戳

为了获取容器空闲事件,必须在容器属性中配置空闲时间间隔,如下所述

KafkaListener将负责将旧事件发送给(以前的新)订阅者:

    @KafkaListener(id = "qux", topics = { "${app.event.topic}" }, errorHandler = "kafkaListenerErrorHandler")
    public void receive(@Payload Event event, @Headers MessageHeaders headers) throws JsonProcessingException {

        // collect the subscribers not marked as new
        Collection<EventListenerSubscription> oldSubscriptions = 
                subscriptions.stream().filter(s -> !s.isNew())
                .collect(Collectors.toList());

        for (EventListenerSubscription s : oldSubscriptions) {
            if (s.getLastTimeStamp() < timestamp) {
                s.addMessage(event, timestamp);
            }
        }
    }
@KafkaListener(id=“qux”,topics={“${app.event.topic}”,errorHandler=“kafkalistenererror