我正在使用Spring Cloud Stream 1.1.2版创建/集成消费者与微服务。我将auto-commit-offset
消费者属性设置为False
,以便我可以在Message中接收确认标头,并在消息被成功使用后手动确认消息。
我担心的是,如果在消息使用过程中出现故障,我不会将确认发送回给代理,但是当我可以期望将相同的消息重新发送给使用者时。目前,只有在重新启动服务器后,我才能验证重新交付,如果服务器已经启动并正在运行,它将如何工作。
消费者属性设置为
kafka:
bindings:
input:
consumer:
auto-commit-offset: false
reset-offsets: true
start-ofofset: earliest
答案 0 :(得分:1)
您需要在客户端中的消息之前查找偏移量。 偏移量在组的kafka服务以及内存中的客户端处保持不变。重启服务时,后者将丢失,这就是为什么您再次使用消息的原因。
这可以通过以下方法解决:
公共类KafkaConsumer实现ConsumerSeekAware {
和
this.seekCallBack.get().seek(consumerRecord.topic(), consumerRecord.partition(), consumerRecord.offset());
希望对您有所帮助!
完整的消费者代码:
public class KafkaConsumer implements ConsumerSeekAware {
private static final String USER_TOPIC = "user-topic";
private static final String USER_LISTENER_ID = "userListener";
private static final String STRING_LISTENER = "string-listener";
private final ThreadLocal<ConsumerSeekCallback> seekCallBack = new ThreadLocal<>();
private final KafkaListenerEndpointRegistry registry;
private final TaskScheduler scheduler;
private final LocalValidatorFactoryBean validatorFactory;
public KafkaConsumer(final KafkaListenerEndpointRegistry registry, final TaskScheduler scheduler, final LocalValidatorFactoryBean validatorFactory) {
this.registry = registry;
this.scheduler = scheduler;
this.validatorFactory = validatorFactory;
}
public void registerSeekCallback(ConsumerSeekAware.ConsumerSeekCallback callback) {
this.seekCallBack.set(callback);
}
@Override
public void onPartitionsAssigned(final Map<TopicPartition, Long> assignments, final ConsumerSeekCallback callback) {
}
@Override
public void onIdleContainer(final Map<TopicPartition, Long> assignments, final ConsumerSeekCallback callback) {
}
@KafkaListener(id = USER_LISTENER_ID, topics = USER_TOPIC, containerFactory = "userContainerFactory")
public void consumeJson(ConsumerRecord<String, User> consumerRecord, User user, final Acknowledgment acknowledgment) {
if (user.getName().equals("reject")) {
throw new IllegalStateException("Illegal user:" + user.getName());
}
if (!user.getName().equals("retry")) {
acknowledgment.acknowledge();
log.info("Consumed JSON Message: " + user);
} else {
log.info("Rejected: " + user);
this.seekCallBack.get().seek(consumerRecord.topic(), consumerRecord.partition(), consumerRecord.offset());
}
}