# SC300：服务未按时退出

> SC300（服务未按时退出）表示到了关闭截止时间，进程仍在运行。找出让 Node 一直运行的未关闭句柄，然后关闭它。

Source: https://shutdown.jscrate.dev/zh/docs/codes/sc300
Last updated: 2026-09-23

`SC300` 表示所有被测试的请求都已完成，但 `shutdown.deadlineMs` 到期时，服务进程仍在运行。HTTP 排空之后，应用里还有东西没有关闭。

| | |
| --- | --- |
| 诊断码 | `SC300` (FAIL) |
| 阶段 | 进程退出 |
| CLI 退出码 | 1 |
| 含义 | 关闭截止时间已过，进程仍在运行。 |
| 输出信息 | `Service did not exit within <shutdown.deadlineMs> ms` |
| 首先检查 | 关闭服务器、数据库连接池和定时器，让事件循环清空；或者在清理完成后显式退出。 |

## 是什么让 Node.js 一直运行？

- HTTP 服务器从未关闭。
- 数据库连接池或队列消费者仍保持连接。
- 某个 interval、文件监听器或后台 worker 仍在运行。
- 清理步骤在等待一个没有超时的操作。
- 包管理器或 shell 包装进程仍在运行。

## 如何修复？

记录每个关闭步骤的开始和结束。按不会阻塞进行中请求的顺序关闭资源，并给外部清理操作加上超时。让事件循环自然清空；避免使用 `process.exit()`，因为它可能打断尚未输出的内容和未完成的请求。

只有在清理耗时符合预期，并且仍低于平台的强制终止时限时，才调大 `deadlineMs`。

## 如何找到未关闭的句柄？

在每个关闭操作前后加日志。在仅用于开发的运行中，查看活动句柄；或者临时移除清理步骤，直到进程能退出，再逐个恢复。

修复后，`process exited — code=0, signal=none` 会出现在截止时间之前。如果进程退出了，端口却仍然开放，继续按 SC302 排查。

## 相关内容

- [优雅关闭时的清理](https://shutdown.jscrate.dev/zh/docs/guides/graceful-shutdown-nodejs)
- [关闭截止时间](https://shutdown.jscrate.dev/zh/docs/configuration#shutdown)
- [SC200：请求未完成](https://shutdown.jscrate.dev/zh/docs/codes/sc200)
- [SC302：端口仍未关闭](https://shutdown.jscrate.dev/zh/docs/codes/sc302)
