我们在应用程序中使用spring-kafka 2.3.0。在以下场景中观察到了一些处理故障
@Service
@EnableScheduling
public class KafkaService {
public void sendToKafkaProducer(String data) {
kafkaTemplate.send(configuration.getProducer().getTopicName(), data);
}
@KafkaListener(id = "consumer_grpA_id",
topics = "#{__listener.getEnvironmentConfiguration().getConsumer().getTopicName()}", groupId = "consumer_grpA", autoStartup = "false")
public void onMessage(ConsumerRecord<String, String> data) throws Exception {
passA(data);
}
private void passB(String message) {
//counter to keep track of retry attempts
if (counter.containsKey(message.getEventID())) {
//RETRY_COUNT = 5
if (counter.get(message.getEventID()) < RETRY_COUNT) {
retryAgain(message);
}
} else {
firstRetryPass(message);
}
}
private void retryAgain(String message) {
counter.put(message.getEventID(), counter.get(message.getEventID()) + 1);
try {
registry.stop(); //pause the listener
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void firstRetryPass(String message) {
// First Time Entry for count and time
counter.put(message.getEventID(), 1);
try {
registry.stop();//pause the listener
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void passA(String message) {
try {
passToTarget(message); //Call target processor
LOGGER.info("Message Processed Successfully to the target");
} catch (Exception e) {
targetUnavailable= true;
passB(message);
}
}
private void passToTarget(String message){
//processor logic, if the target is not available, retry after 15 mins, call passB func
}
@Scheduled(cron = "0 0/15 * 1/1 * ?")
public void scheduledMethod() {
try {
if (targetUnavailable) {
registry.start();
firstTimeStart = false;
}
LOGGER.info(">>>Scheduler Running ?>>>" + registry.isRunning());
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
}
}
答案 0 :(得分:0)
除非使用stop(Runnable)
,否则不应该在侦听器线程上停止注册表-否则,由于容器等待侦听器退出,因此将出现死锁和延迟。
在处理完由上次轮询获取的所有剩余记录之前(除非您设置了max.poll.records=1
。)(通过注册表)停止容器实际上不会生效。
当侦听器正常退出时,将提交记录的偏移量,以使记录不会在下次启动时重新分发。
您可以在此用例中使用ContainerStoppingErrorHandler
。参见here。
引发异常,错误处理程序将为您停止容器。
但这会在第一次尝试时停止容器。
如果要重试,请使用SeekToCurrentErrorHandler
并在重试用尽后从恢复器中调用ContainerStoppingErrorHandler
。