同一流应用程序中的Kafka流关闭挂钩和意外异常处理

时间:2018-09-27 02:50:17

标签: java exception-handling apache-kafka apache-kafka-streams shutdown-hook

我的任务是拆除开发环境,然后从废料中重新进行设置,以验证我们的CI-CD流程;唯一的问题是我搞砸了创建一个主题,因此Kafka Streams应用程序退出并出现错误。

我仔细研究了一下,找到了问题并纠正了它,但是当我进行挖掘时,遇到了另一个奇怪的小问题。

我这样实现了意外异常处理程序:

streams.setUncaughtExceptionHandler((t, e) -> {
    logger.fatal("Caught unhandled Kafka Streams Exception:", e);
    // Do some exception handling.
    streams.close();

    // Maybe do some more exception handling.
    // Open a lock that is waiting after streams.start() call 
    // to let application exit normally
    shutdownLatch.countDown();
});

问题在于,如果在调用KafkaStreams :: close时应用程序由于主题错误而引发异常,则在尝试调用KafkaStreams :: waitOnState之后,应用程序似乎在WindowsSelectorImpl :: poll中死锁了。

我认为在异常处理程序中调用KafkaStreams :: close可能是一个问题,但我发现了这个SOMatthias J. Sax的评论,称可以调用KafkaStreams :: Close应该没问题注意在异常处理程序中不要从多个线程调用KafkaStreams :: close。

问题是我想实现一个关闭钩子,以根据请求优雅地杀死Steams应用程序,并实现UnexpectedException处理程序,以在出现异常情况时优雅地清理并终止。

我想出了以下解决方案,该解决方案在调用close之前先检查KafkaStreams的状态,它确实可以工作,但是似乎有点,因为除了运行(也许正在等待)之外,我还可以看到其他情况,我们希望确保KafkaStreams的运行::关闭它的调用。

Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    logger.fatal("Caught Shutdown request");
    // Do some shutdown cleanup.
    if (streams.state().isRunning())
    {
        If this hook is called due to the Main exiting after handling 
        an exception we don't want to call close again. It doesn't 
        cause any errors but logs that the application was closed 
        a second time.
        streams.close(100L, TimeUnit.MILLISECONDS);
    }
    // Maybe do a little bit more clean up before system exits.
    System.exit(0);

}));

streams.setUncaughtExceptionHandler((t, e) -> {
    logger.fatal("Caught unhandled Kafka Streams Exception:", e);
    // Do some exception handling.
    if (streams.state().isRunning())
    {
        streams.close(100L, TimeUnit.MILLISECONDS);
    }
    // Maybe do some more exception handling.

    // Open the Gate to let application exit normally
    shutdownLatch.countDown();
    // Or Optionally call halt to immediately terminate and prevent call to Shutdown hook.
    Runtime.getRuntime().halt(0);
});

关于为什么在异常处理程序中调用KafkaSteams:close的任何建议都会引起此类麻烦,或者是否有更好的方法同时实现关机钩子和异常处理程序,将不胜感激?

1 个答案:

答案 0 :(得分:1)

从异常处理程序和关闭挂钩中调用import matplotlib.pyplot as plt plt.plot([.005,.005],[1,2]) plt.xscale('log') plt.yscale('log') plt.show() 稍有不同。如果close()从关闭挂接中调用(请参阅https://issues.apache.org/jira/browse/KAFKA-4366)可能会死锁,因此,您应该在超时时调用它。

此外,此问题与Jira中所述的从未捕获的异常处理程序中调用close()有关。通常,打电话给System.exit()很苛刻,应避免恕我直言。

您的解决方案似乎也不是100%健壮的,因为System.exit()可能会导致竞争。

使用超时的一种替代方法可能是,仅在关机钩子和异常处理程序中都设置一个streams.state().isRunning(),如果布尔标志设置为true,则使用“ main()”线程调用close:

AtomicBoolean