背景
最近收到一个新需求,需要充kafka队列中那消息解析写到es中。要求不能漏写数据,或者重复写数据。‘
问题
如果程序中途需要手动停止,就需要把已经从kafka中拿到的数据,写进了es 才能停止程序。否则就会漏写数据或者重复写入数据
解决
钩子函数
ShutdownHook只是一个已初始化但为启动的线程。当JVM开始执行关闭序列时,它才开始已某种随机程序注册和并行执行shutdown hooks。
注意 这个对 kill -9 {pid} 无效,对 kill -15 及 Control +C 有效
//注册钩子函数
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("开始停止任务");
//停止标识位 为 true 停止从kafka 拿数据
isStop = true;
try {
//阻塞 直到将已经拿到的数据处理完毕
executorService.awaitTermination(1, TimeUnit.HOURS);
} catch (Exception e) {
e.printStackTrace();
}
log.info("任务已经停止");
}));
SignalHandler
实现sun.misc.SignalHandler 接口
public class SignalHandlerImp implements SignalHandler {
public void handle(Signal signal) {
//停止标识位 为 true 停止从kafka 拿数据
isStop = true;
try {
//阻塞 直到将已经拿到的数据处理完毕
executorService.awaitTermination(1, TimeUnit.HOURS);
} catch (Exception e) {
e.printStackTrace();
}
log.info("任务已经停止");
System.out.println(signal.getName()+":"+signal.getNumber());
}
}
// 注册要监听的信号
SignalHandlerImp signalHandlerImp = new SignalHandlerImp();
Signal.handle(new Signal("INT"), signalHandlerImp);// 2 : 中断(同 ctrl + c )
Signal.handle(new Signal("TERM"), signalHandlerImp);// 15 : 正常终止
Signal.handle(new Signal("USR2"), signalHandlerImp);// 12 : 用户自定义信号
总结
jvm 关闭的几种方式
我们可以通过 钩子函数来 处理 正常关闭以及异常关闭的收尾工作。SignalHandler 只能处理正常关闭的收尾工作。所以钩子函数的应用要广泛一点的。