Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在生成事件B后手动确认Kafka事件A_Java_Spring_Spring Boot_Apache Kafka_Spring Kafka - Fatal编程技术网

Java 在生成事件B后手动确认Kafka事件A

Java 在生成事件B后手动确认Kafka事件A,java,spring,spring-boot,apache-kafka,spring-kafka,Java,Spring,Spring Boot,Apache Kafka,Spring Kafka,我有一个案例,我必须使用事件a并进行一些处理,然后生成事件B。因此,我的问题是,如果处理崩溃,应用程序无法生成B,而它已经使用了a。我的方法是在成功发布B之后进行确认,我是正确的还是应该为这种情况实施另一种解决方案 @KafkaListener( id = TOPIC_ID, topics = TOPIC_ID, groupId = GROUP_ID, containerFactory = LISTENER_CONTAINER_FA

我有一个案例,我必须使用事件a并进行一些处理,然后生成事件B。因此,我的问题是,如果处理崩溃,应用程序无法生成B,而它已经使用了a。我的方法是在成功发布B之后进行确认,我是正确的还是应该为这种情况实施另一种解决方案

@KafkaListener(
        id = TOPIC_ID,
        topics = TOPIC_ID,
        groupId = GROUP_ID,
        containerFactory = LISTENER_CONTAINER_FACTORY
)
public void listen(List<Message<A>> messages, Acknowledgment acknowledgment) {

    try {
        final AEvent aEvent = messages.stream()
                .filter(message -> null != message.getPayload())
                .map(Message::getPayload)
                .findFirst()
                .get();

        processDao.doSomeProcessing() // returns a Mono<Example> by calling an externe API
                .subscribe(
                        response -> {
                            ProducerRecord<String, BEvent> BEventRecord = new ProducerRecord<>(TOPIC_ID, null, BEvent);

                            ListenableFuture<SendResult<String, BEvent>> future = kafkaProducerTemplate.send(buildBEvent());
                            future.addCallback(new ListenableFutureCallback<SendResult<String, BEvent>>() {
                                @Override
                                public void onSuccess(SendResult<String, BEvent> BEventSendResult) {
                                    //TODO: do when event published successfully
                                }

                                @Override
                                public void onFailure(Throwable exception) {
                                    exception.printStackTrace();
                                    throw new ExampleException();
                                }
                            });
                        },
                        error -> {
                            error.printStackTrace();
                            throw new ExampleException();
                        }
                );
        acknowledgment.acknowledge(); // ??
    } catch (ExampleException) {
        exception.printStackTrace();
    }
}
@KafkaListener(
id=主题_id,
topics=TOPIC\u ID,
groupId=组\u ID,
containerFactory=侦听器\u容器\u工厂
)
公共无效侦听(列出消息、确认){
试一试{
final AEvent AEvent=messages.stream()
.filter(message->null!=message.getPayload())
.map(消息::getPayload)
.findFirst()
.get();
processDao.doSomeProcessing()//通过调用外部API返回Mono
.订阅(
答复->{
ProducerRecord BEventRecord=新的ProducerRecord(主题ID,null,BEvent);
ListenableFuture=kafkaProducerTemplate.send(buildBEvent());
future.addCallback(新ListenableFutureCallback(){
@凌驾
成功时公共无效(SendResult BEventSendResult){
//TODO:成功发布事件时执行的操作
}
@凌驾
失败时公共无效(可丢弃的例外){
异常。printStackTrace();
抛出新的ExampleException();
}
});
},
错误->{
错误。printStackTrace();
抛出新的ExampleException();
}
);
确认。确认();/??
}捕获(例如异常){
异常。printStackTrace();
}
}
使用异步代码(如reactor)时,您无法管理卡夫卡的“确认”

Kafka不管理每个主题/分区的离散ACK,只管理分区的最后提交偏移量

如果您异步处理两条记录,您将有一个关于首先提交哪个偏移量的竞争


您需要在侦听器容器线程上执行发送,以保持正确的顺序。

在这种情况下,如何使用侦听线程?你能不能给我一个提示,我应该如何重构代码以获得正确的顺序?谢谢,我现在反应不太好,但我认为您需要在
Mono
上调用
block()
,而不是
subscribe()
,并使用结果发送消息。然后,您可以在将来完成时调用acknowledge,或者抛出异常并配置
seektocurInterrorHandler
,以便重新传递记录。但是,您确实不需要使用手动确认,
AckMode.BATCH
(默认值)将在侦听器正常退出时导致容器提交偏移量;您将需要更复杂的功能—保留您的订阅者,并使用某种闩锁来保持侦听器线程,直到所有处理完成。e、 g.
new CountDownLatch(messages.size())
并在每次完成时对闩锁进行倒计时,以便在完成所有操作后释放侦听器线程。如果我理解清楚,请使用错误处理程序
seektocurinterrorHandler
(类似),我的应用程序将再次侦听同一消息,直到流程正常完成,因此无需实现手动aknowledge,对吗?正确-但请记住,使用批处理侦听器;
SeekToCurrentBatchErrorHandler
无法知道批处理中的哪个记录失败,因此无法恢复,记录将无限期地重新传递。对于暂时性错误,这是可以的,但通常,对于批处理侦听器,错误处理/恢复必须在侦听器本身中完成。您仍然可以使用
seektocurrentbackerrorhandler
,但是如果同一条记录一再失败,您需要侦听器中的一些逻辑来放弃。