优雅关停
线上部署要的就是干净收尾:Kubernetes 发 SIGTERM 时,进程必须先把在飞的 handler 跑完再关 broker socket,否则消息会处理到一半被丢。
app.stop() 默认就走 drain:拒绝新的入站 dispatch、等所有 route 的 inflight 归零(或超时),再依次跑 onStop hook、取消未完成的 RPC、关闭 broker adapter。
API
ts
await app.stop({
drain: true, // 默认;传 false 走老的立即关闭
timeout: 30_000, // 最多等多少毫秒
})app.activeCount() 返回当前在飞总数,做健康检查或 drain 过程的日志很合适。
SIGTERM 接线
ts
const shutdown = async (signal: NodeJS.Signals) => {
console.log(`[server] received ${signal}, draining…`)
await app.stop({ drain: true, timeout: 30_000 })
process.exit(0)
}
process.once('SIGTERM', shutdown)
process.once('SIGINT', shutdown)执行顺序
不做的事
- Broker 在 drain 期间仍接受新 TCP 连接。 mqttkit 只拒绝 dispatch,自带的 Aedes adapter 并不会暂停 listener。要做无感滚动发布,请先在负载均衡 / readiness probe 上把流量切走。
- 不会取消 handler。 JavaScript 没有抢占——handler 死循环就只会撞 drain 超时然后打 warning。配合 route 级
timeout防止个别 handler 阻塞整个 drain。 - 不会重发失败的 publish。 需要在
onStop里 flush 状态的,自行await publish。
超时行为
drain 超时但仍有 handler 在跑:
app.stop()打印[mqttkit] stop() drain timed out after Xms; N handler(s) still in-flight。- 关停流程继续——
onStop跑、RPC 取消、broker 关闭。 - 残留的 handler 仍会一路跑到底,或者跟着进程退出一起死。
超时按 SLA 调:通常取「最长合理 handler 运行时间 + 少量 buffer」。