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