Vert.x Java应用Shutdown Hook日志不全问题求助
问题
我们有一个Vert.x Java应用,需要在关闭时记录相关信息。但按下CTRL+C或关闭应用时,仅打印出“Shutting down...”这一条日志。相关代码如下:
Runtime.getRuntime().addShutdownHook(new Thread(serviceStatusLogger::log)); final Vertx vertx = Vertx.vertx(); final HttpServer server = vertx.createHttpServer(); final Router router = Router.router(Vertx.vertx()); final Route route = router.route(HttpMethod.GET, "/health"); route.handler(request -> { final HttpServerResponse response = request.response(); response.putHeader("content-type", "text/plain"); response.end(makeResponse()); }); server.requestHandler(router).listen(8085);
ServiceStatusLogger类代码:
public class ServiceStatusLogger { private static final Logger LOG = Logger.getLogger(ServiceStatusLogger.class.getName()); private final DefaultMessageResolver defaultMessageResolver; private final WebhookResponseRepository webhookResponseRepository; public ServiceStatusLogger(final DefaultMessageResolver defaultMessageResolver, final WebhookResponseRepository webhookResponseRepository) { this.defaultMessageResolver = defaultMessageResolver; this.webhookResponseRepository = webhookResponseRepository; } public void log(){ LOG.info("Shutting down..."); LOG.info("Last processed webhook response log id: " + webhookResponseRepository .getLastWebhookResponseLog() .getId()); LOG.info("Total number of webhooks processed in this job execution: " + defaultMessageResolver.getWebhooksProcessed()); } }
解决方案
问题根源是你用了JVM原生的Runtime.shutdownHook,但Vert.x有自己的生命周期管理流程。当收到关闭信号时,Vert.x可能已经提前销毁了webhookResponseRepository或defaultMessageResolver依赖的资源,导致后续日志代码抛出未捕获异常,所以只输出了第一条日志。
按以下步骤调整即可解决:
移除JVM shutdown hook,改用Vert.x的关闭回调
Vert.x提供的vertx.closeHandler()会在Vert.x启动关闭流程时触发,此时所有Vert.x管理的资源还未被销毁,依赖对象仍可正常调用。修改代码绑定Vertx生命周期
调整启动代码,注册Vert.x关闭处理器,并复用同一个Vertx实例创建路由(避免资源分散):
final Vertx vertx = Vertx.vertx(); final HttpServer server = vertx.createHttpServer(); // 注册Vert.x关闭回调 vertx.closeHandler(v -> { serviceStatusLogger.log(); }); // 复用已创建的vertx实例,不要重新调用Vertx.vertx() final Router router = Router.router(vertx); final Route route = router.route(HttpMethod.GET, "/health"); route.handler(request -> { final HttpServerResponse response = request.response(); response.putHeader("content-type", "text/plain"); response.end(makeResponse()); }); server.requestHandler(router).listen(8085);
- 添加异常捕获(推荐)
为防止log()方法中出现异常导致日志中断,可在回调中捕获异常:
vertx.closeHandler(v -> { try { serviceStatusLogger.log(); } catch (Exception e) { LOG.severe("Failed to log shutdown status: " + e.getMessage()); } });
调整后,应用关闭时会先执行完整的日志记录逻辑,再逐步销毁资源,所有日志就能正常打印。
内容的提问来源于stack exchange,提问作者fragilepriCe
相关产品推荐
相关产品推荐

