@x-9lab/xlab 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -68,8 +68,6 @@ declare global {
68
68
  staticMaxage?: number;
69
69
  /**静态 html 文件缓存时间 */
70
70
  staticHtmlFileMaxage?: number;
71
- /**是否开启 Combo 缓存 */
72
- enableComboCache?: boolean;
73
71
  /**是否开启定时任务 */
74
72
  enableCron?: boolean;
75
73
  /**是否允许 worker 上也执行定时任务 */
package/MIGRATION.md CHANGED
@@ -68,7 +68,13 @@ grep -rln "requireMod\|requireModel\|requireService\|getSysConfig\|setSysConfig\
68
68
 
69
69
  ### 3. 数组形式的路由改写(必做,如有)
70
70
 
71
- 数组导出(文件名当方法名)已移除,启动时命中会直接报错。改写方式二选一:
71
+ 数组导出(文件名当方法名)已移除,启动时命中会直接报错。先用下面的命令排查(**注意同时覆盖 CJS 与 ESM 两种写法**,只搜其中一种会漏):
72
+
73
+ ```bash
74
+ grep -rnE "module\.exports\s*=\s*\[|export default \[" @server/business/
75
+ ```
76
+
77
+ 改写方式二选一:
72
78
 
73
79
  ```js
74
80
  // v1: @server/business/user/post.js —— 数组形式
@@ -112,11 +118,11 @@ module.exports = {
112
118
 
113
119
  以下变化不需要改代码,但需要确认对业务无影响:
114
120
 
115
- 1. **优雅退出**:收到 SIGTERM/SIGINT 后,服务会停止定时任务 → 等待在途请求(默认 10s,可用配置项 `shutdownTimeout` 调整,单位毫秒)→ 执行 `shutdown` 钩子 → 退出。**部署侧注意**:k8s 的 `terminationGracePeriodSeconds`、pm2 的 `kill_timeout` 需要大于 `shutdownTimeout`,否则会被强杀。
116
- 2. **worker 崩溃重启退避**:cluster 模式下 worker 10 秒内连续快速崩溃 5 次后不再自动拉起(v1 无条件立即重启,会造成 crash-loop)。依赖「无限重启」兜底的业务需要检查告警。
121
+ 1. **优雅退出**:收到 SIGTERM/SIGINT 后,服务会停止定时任务 → 等待在途请求(默认 10s,可用配置项 `shutdownTimeout` 调整,单位毫秒)→ 执行 `shutdown` 钩子 → 退出。**部署侧注意**:k8s 的 `terminationGracePeriodSeconds`、pm2 的 `kill_timeout` 必须大于 `shutdownTimeout`,推荐 **`shutdownTimeout + 5s` 以上**(默认配置下即 ≥ 15s),否则优雅退出会被强杀。
122
+ 2. **worker 崩溃重启退避**:cluster 模式下 worker 10 秒内连续快速崩溃 5 次后不再自动拉起(v1 无条件立即重启,会造成 crash-loop)。依赖「无限重启」兜底的业务需要检查告警;退避触发时 master 会输出 error 级日志,可用关键字 **`停止自动拉起`** 接入日志告警。
117
123
  3. **business 根级 `$` 中间件开始生效**:v1 因 bug 从不生效,v2 按文档约定对全部业务路由生效。如果 business 根下有 `$` 目录,确认其中间件对所有接口执行是否符合预期。
118
124
  4. **`crons` 按任务配置开始生效**:配置项 `crons: { 任务文件名: { delay, enable } }` v1 只有类型声明没有实现,v2 起真实生效,优先级高于任务模块自身的 `getDelay()` / `enable()`。注意 `delay` 单位是**秒**(与 `cron.def` 一致),模块 `getDelay()` 返回值仍是毫秒。
119
- 5. **`middleware` 数组配置移除**:v1.1.0 起已弃用且实际不被读取,配置里如仍保留该字段可直接删除,只认 `middlewares`。
125
+ 5. **`middleware` 数组配置移除**:v1.1.0 起已弃用且实际不被读取,配置里如仍保留该字段可直接删除,只认 `middlewares`。同时移除 `enableComboCache` 配置与内置中间件白名单里的 `combo` 项——combo 中间件实现早已不存在,v1 中启用它会直接启动崩溃。
120
126
  6. **`custom` 的执行时机**:v1 对 async 自定义模块不等待;v2 会 await 完 `setup` 才继续装配中间件与路由,时序更明确。
121
127
  7. **方法名文件的 api 路径会变化(重要)**:v1 中名为 `get.js` / `post.js` 等的函数或对象形态路由文件,文件名会进入 api 路径(如 `business/foo/post.js` → `POST /api/foo/post`);v2 按「文件名即方法」约定,文件名不再进入路径(→ `POST /api/foo`)。**这是路由地址的静默变更**,升级前用下面命令找出此类文件,逐个确认调用方,必要时用 `defineApi` 的 `api` 字段固定回原地址:
122
128
 
@@ -151,6 +157,12 @@ import {
151
157
 
152
158
  ## 常见问题
153
159
 
160
+ **Q: 共享库(被多个业务引用的包)怎么迁移?**
161
+ v2 的 `requireMod` / `getLogger` 等 API 不依赖框架 boot 状态,`require("@x-9lab/xlab")` 后即可独立使用。因此共享库可以先行直迁 v2 显式导入,在 v1/v2 混装的过渡期也能安全加载。注意 `getSysConfig` / `getXlabEnv` 的**数据**在 boot 后才填充,共享库应在调用时读取,不要在模块加载时缓存取值。
162
+
163
+ **Q: monorepo 混装期(部分包 v1、部分包 v2)有什么已知现象?**
164
+ 根 node_modules 的提升版本会随多数派翻转;v1/v2 全局类型声明并存时,tsc 可能报 node_modules 内的重复标识符,属预期噪音,全部迁移完成后消失。
165
+
154
166
  **Q: 迁移时想先跑起来再逐步改,有没有临时兼容方案?**
155
167
  可以在业务自己的 `@server/@env/index.js`(启动最早执行)里临时把 API 挂回 global,迁移完成后删除:
156
168
 
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  X-9lab 通用服务端
2
2
  =======
3
3
 
4
+ > 当前为 v2 版本(breaking change),从 v1 升级请先阅读 [MIGRATION.md](./MIGRATION.md)。
5
+
4
6
  ## 开发环境配置
5
7
  1. 安装 [node](https://nodejs.org/) ,需要 20.0.0 以上版本
6
8
 
@@ -18,14 +20,21 @@ X-9lab 通用服务端
18
20
  ```bash
19
21
  xlab --APP_NAME=nice
20
22
  ```
23
+ - 其他命令行参数
24
+ - `-w` / `--watch` 开启 watch 模式
25
+ - `-r` / `--root` 指定执行根目录
26
+ - `-f` / `--file` 指定启动配置文件地址
27
+ - `PORT=3001` 覆盖监听端口,`IP=127.0.0.1` 指定绑定地址,`ENV=<环境>` 指定运行环境
28
+ - 运行环境
29
+ 由 `ENV=` 参数或 `NODE_ENV` 决定,支持 `development`(开发) / `sandbox`(沙箱) / `production`(生产),也可使用数字别名 `0` / `2` / `1`;未指定时默认 development。环境决定加载哪份 `@config` 环境配置与 `.xlab` 环境文件
21
30
  - 配置文件 `xlab.config.js`
22
31
  模块会自动检测执行根目录中是否存在 `xlab.config.js` 文件。如存在该文件则会使用该文件为模块的启动配置文件。支持的配置项:
23
32
  1. `watch` 是否开启 watch 模式
24
- 1. `business` 业务目录名称。注意当前只支持根目录下的文件夹
33
+ 1. `businessDir` 服务端业务目录名称,默认 `@server`。注意当前只支持根目录下的文件夹
25
34
  - 配置文件 `.xlab`
26
- 该文件用于定义系统中的全局变量,模块会自动检测执行根目录中是否存在 `.xlab` 文件。该类型文件一般用于定义一些不方便在代码中声明的敏感数据,因此 `.xlab` 及附属的环境文件 **不应该** 被提交到仓库中。
27
- - 使用 `<key>=<value>` 的方式定义数据
28
- - 文件中的数据会被加载到 `global.XLAB` 对象中
35
+ 该文件用于定义系统级的环境数据,模块会自动检测执行根目录中是否存在 `.xlab` 文件。该类型文件一般用于定义一些不方便在代码中声明的敏感数据,因此 `.xlab` 及附属的环境文件 **不应该** 被提交到仓库中。
36
+ - 使用 `<key>=<value>` 的方式定义数据,value 按 JSON 解析
37
+ - 文件中的数据通过 `getXlabEnv()` 获取
29
38
  - `.xlab` 为生产环境定义,`.xlab.development` 为开发环境定义,`.xlab.sandbox` 为沙箱环境定义
30
39
  - `watch` 模式
31
40
  `xlab` 支持自动重启业务,开发中使用该功能可以减少大量手动重启业务的操作。
@@ -42,6 +51,7 @@ X-9lab 通用服务端
42
51
  ```
43
52
  - 除了静态资源,服务端业务需要放在项目根目录下的 `@server` 目录中
44
53
  - 支持业务自定义以下内容 (无特殊说明的都是存放在 @server 目录中)
54
+ - 环境预处理,存放于 `@env` 目录(可选),`@env/index.js` 会在启动最早阶段(配置装载前)被执行,可用于设置 `process.env` 等
45
55
  - 配置项,存放于 `@config` 目录
46
56
  - 支持不同环境配置文件
47
57
  - 无中间词缀的 config 文件为生产环境配置文件
@@ -70,13 +80,23 @@ X-9lab 通用服务端
70
80
  - 以 `$` 开头的文件夹, 该文件夹中的文件会成为后续接口的通用中间件,可以用于某类型业务的统一处理,如后台某些接口的额外身份处理。为了防止滥用,该文件夹不会递归查找,也就是说不支持子文件夹的组织形式。
71
81
  - 整个 api 地址的每个父层都可以有独立的中间件文件,执行顺序会按照目录层级执行
72
82
  - 中间件文件夹内的文件只会按照文件名做简单排序,因此请特别注意执行顺序是否符合自己的预期,或采用带序号的文件名
73
- - 自定义逻辑,存放于 `custom` 目录,模块导出一个函数作为执行入口(视为 `setup`),或导出 `{ setup, ready, shutdown }` 生命周期钩子对象
83
+ - 自定义逻辑,存放于 `custom` 目录,需在配置项 `custom` 数组中声明才会执行(`"模块名"` 或 `["模块名", 参数]`)。模块导出一个函数作为执行入口(视为 `setup`),或导出 `{ setup, ready, shutdown }` 生命周期钩子对象
74
84
  - `setup` 服务装配前执行,接收 `custom` 配置中声明的参数
75
85
  - `ready` 服务启动完成(listen 成功)后执行
76
86
  - `shutdown` 服务退出前执行,可用于释放连接等资源
77
- - 中间件,存放于 `middleware` 目录
78
- - 定时任务,存放于 `cron` 目录
79
- - 静态资源,默认存放在项目根目录下的 `public` 目录中
87
+ - 中间件,存放于 `middleware` 目录,通过配置项 `middlewares` 启用与排序
88
+ - 名称命中内置中间件时加载内置实现,否则加载业务 `middleware` 目录下的同名模块;模块需导出工厂函数 `(config) => koaMiddleware`
89
+ - 内置中间件:`bad-request`(异常返回兜底,总是启用)、`fresh-filter`(304 协商缓存)、`handle-pre-dir`(代理路径层级处理)、`request-filter`(请求过滤)、`service-mark`(X-Mark 服务标识)、`compress`(压缩)、`cors`(跨域)
90
+ ```js
91
+ "middlewares": {
92
+ "service-mark": true
93
+ , "cors": { "config": { "type": "sameroot" } }
94
+ }
95
+ ```
96
+ - 定时任务,存放于 `cron` 目录,由配置项 `enableCron` 开启,默认只在 master 进程执行(`enableWorkerCron` 可放开到 worker)
97
+ - 任务模块导出一个函数作为任务体,可另外导出 `getDelay()`(间隔,毫秒) 与 `enable()`(开关)
98
+ - 配置项 `crons` 可按文件名覆盖任务的间隔与开关,优先级高于模块自身导出
99
+ - 静态资源,默认存放在项目根目录下的 `public` 目录中(配置项 `root` 可改)
80
100
  ### 模块 API
81
101
 
82
102
  v2 起框架 API 不再挂载到 global,统一从包导入(v1 升级请看 [MIGRATION.md](./MIGRATION.md)):
@@ -95,6 +115,7 @@ const {
95
115
 
96
116
  - `getLogger(cat)` 获取分类日志实例
97
117
  - `masterLog(cat, type?, ...msg)` 只在 master 进程上输出的日志方法
118
+ - `requireMod` / `getLogger` 等不依赖服务启动状态,共享库可独立引用;`getSysConfig` / `getXlabEnv` 的数据在启动后才填充,应在调用时读取
98
119
  - `getApp` 获取应用实例对象
99
120
  ```ts
100
121
  /**
@@ -129,6 +150,7 @@ const {
129
150
  function setSysConfig(conf: XLab.IConfig): void;
130
151
  ```
131
152
  - `getXlabEnv` 获取 `.xlab` 系列文件定义的环境数据
153
+ - `boot` 启动服务,按固定阶段装配并监听;正常业务由 `xlab` 命令调用,无需手动执行
132
154
  - `shutdown` 优雅退出:停止定时任务 → 等待在途请求 → 执行 `shutdown` 钩子 → 退出进程;收到 `SIGTERM` / `SIGINT` 时自动触发
133
155
  - `requireModel` 获取 model 的方法
134
156
  该方法只是为获取 model 提供一个快捷方式,也可以通过正常的方式去 require
@@ -186,87 +208,64 @@ const {
186
208
  |-|-|-|-|
187
209
  |name|`string`| package.json 中的 name 字段 |服务(应用)名称|
188
210
  |version|`string`|package.json 中的 version 字段|版本|
189
- |env|`string`|development|环境标识|
190
- |host|`string`| |业务绑定的域名|
211
+ |env|`string`|DEVELOPMENT|环境标识(大写),由启动环境决定,业务不应配置|
212
+ |host|`string`| |业务绑定的域名,cors 中间件 `sameroot` 模式使用|
191
213
  |304|`boolean`| true |是否开启 304 协商缓存|
192
- |workers|`number`|0|Worker 数量|
193
- |biServer|`string`||业务服务器地址|
194
- |protocol|`string`|http|业务服务器协议|
195
- |debug|`boolean`|false|是否开启 debug 模式|
196
- |staticMaxage|`number`|1800000|静态文件缓存时间|
214
+ |workers|`number`|0|Worker 数量,大于 0 时以 cluster 模式启动|
215
+ |ip|`string`||服务绑定地址,也可通过 `IP=` 命令行参数指定|
216
+ |timezone|`string`|Asia/Shanghai|时区|
217
+ |debug|`boolean`|非生产环境为 true|是否开启 debug 模式|
218
+ |staticMaxage|`number`|1800000|静态文件缓存时间(仅生产环境启用)|
197
219
  |staticHtmlFileMaxage|`number`|0|静态 html 文件缓存时间|
198
220
  |staticCros|`boolean`|false|是否允许静态资源跨域访问|
199
- |enableComboCache|`boolean`|true|是否开启 Combo 缓存|
200
221
  |enableCron|`boolean`|false|是否开启定时任务|
201
222
  |enableWorkerCron|`boolean`|false|是否允许 worker 上也执行定时任务|
202
223
  |middlewares|`Record<string, MiddlewareConfig>`|{}|开启的中间件列表 |
203
224
  ||MiddlewareConfig||`index` 用于定义中间件位置,不提供将使用配置对象中的默认顺序<br/> `name` 中间件名称,不提供将使用配置对象的键名<br/>`config` 中间件配置|
204
225
  |custom|`(string | [string, any])[]`||自定模块配置,元组形式可传入参数|
205
226
  |mark|`string`|name 配置|服务标识,用于 service-mark 中间件|
206
- |strictSSL|`boolean`||是否启用严格 ssl|
207
- |apis|`Record<string, string>`|{}|页端注入的 api 设置|
208
- |hasLo|`boolean`||本地是否存在本地开发配置文件|
209
- |passExtApis|`boolean`||不处理业务 api|
210
- |allowCache|`boolean`||是否允许页端缓存|
227
+ |apis|`Record<string, string>`|{}|页端注入的 api 设置,自动合并 `@config/@apis` 目录内容|
228
+ |hasLo|`boolean`||本地是否存在本地开发配置文件,由框架自动设置|
229
+ |passExtApis|`boolean`||不合并 `@config/@apis` 目录的 api 配置|
230
+ |allowCache|`boolean`|true|是否允许页端缓存|
211
231
  |root|`string`|public|静态文件根目录|
212
- |port|`number`|5000|监听端口|
213
- |isMaster|`boolean`||是否是主进程|
214
- |clearLocalStorage|`boolean`||是否每次都强制清除 LocalStorage|
215
- |pathReplaceRegExp|`string`||处理代理过来多余的地址层级路径替换判断正则|
232
+ |port|`number`|5000|监听端口,也可通过 `PORT=` 命令行参数指定|
233
+ |isMaster|`boolean`||是否是主进程,由框架自动设置|
234
+ |pathReplaceRegExp|`string`||handle-pre-dir 中间件处理代理多余地址层级的判断正则|
216
235
  |routeMobile|`string`||移动端入口文件地址(旧版逻辑)|
217
- |launchRouter|`Record<string, string>`||不同端入口地址设置, 由 `@x-drive/launch-detect` 提供支持|
218
236
  |cron|`{def?: number;}`|{"def": 60}|定时任务设置,`def` 为默认间隔(秒)|
219
237
  |crons|`Record<string, {delay?: number; enable?: boolean;}>`||按任务(文件名)的定时任务配置,`delay` 单位秒,优先级高于任务模块自身的 `getDelay()` / `enable()`|
220
238
  |shutdownTimeout|`number`|10000|优雅退出时等待在途请求/worker 结束的超时时间(毫秒)|
221
- |injection|`string[]`|[]|注入参数列表|
222
- |indexPageCacheTime|`number`||首页缓存时间|
223
- |staticResourceCacheTime|`number`||静态资源缓存时间|
239
+ |indexPageCacheTime|`number`||fresh-filter 中间件的首页缓存时间(毫秒)|
240
+ |staticResourceCacheTime|`number`||fresh-filter 中间件的静态资源缓存时间(毫秒)|
241
+ |biServer / protocol / strictSSL / internalServers / internalApis|||框架不读取的业务约定字段,供业务通过 `getSysConfig` 自取|
242
+
243
+ > v2 起移除:`middleware`(数组形式,v1.1.0 已弃用)、`enableComboCache` 与 `launchRouter`(对应实现已不存在)。
224
244
 
225
- ## 文件结构
245
+ ## 业务项目文件结构
226
246
 
227
247
  ```
228
- ├── README.md
229
- ├── business
230
- │ └── @services
231
- │ └── @models
232
- │ │ └── forumUser.js
233
- └── ...
234
- ├── components
235
- ├── cache
236
- ├── common.js
237
- │ └── ...
238
- ├── @config
239
- │ ├── config.dev.ts
240
- └── config.ts
241
- ├── middleware
242
- ├── cron
243
- ├── public
244
- ├── test
245
- ├── route
246
- ├── private
247
- │ └── log
248
- ├── package.json
249
- ├── config.js
250
- ├── router.js
251
- └── server.js
248
+ 业务项目根目录
249
+ ├── package.json # scripts 中调用 xlab 启动
250
+ ├── xlab.config.js # 启动配置(watch / businessDir),可选
251
+ ├── .xlab # 环境数据文件(.xlab.development / .xlab.sandbox),不入库
252
+ ├── public # 静态资源(root 配置可改)
253
+ └── @server # 服务端业务目录(businessDir 配置可改)
254
+ ├── @env # 环境预处理,启动最早执行,可选
255
+ └── index.js
256
+ ├── @config # 配置: config.js / config.dev.js / config.sand.js / config.lo.js
257
+ │ └── @apis # 页端注入的 api 配置,可选
258
+ ├── business # 约定路由目录,按目录结构生成 /api/...
259
+ │ ├── @models # model,requireModel 读取
260
+ ├── @services # service,requireService 读取
261
+ ├── $mws # $ 前缀目录级中间件
262
+ │ └── ...
263
+ ├── middleware # 业务中间件,middlewares 配置启用
264
+ ├── custom # 自定义逻辑与生命周期钩子,custom 配置声明
265
+ └── cron # 定时任务,enableCron 开启
252
266
  ```
253
267
 
254
- ### 说明
255
- - ``business目录``:前端业务
256
- - ``@services目录``:业务services
257
- - ``@models目录``:存放model
258
- - ``components目录``: 存放当前项目组件
259
- - ``@config``:存放环境配置,不同环境在名称与文件后缀中间使用不同代号区分
260
- - ``middleware目录``:存放请求特殊处理模块,一般作为中间件
261
- - ``public目录``:存放前端资源文件
262
- - ``cron目录``:存放定时任务文件
263
- - ``test目录``:存放单元测试
264
- - ``route目录``:存放不同平台的路由配置
265
- - ``private目录``:存放业务 log ,或其他服务端相关的内容
266
- - ``package.json``:nodejs后端所需要的依赖描述文件,即npm的 [package.json](https://www.npmjs.org/doc/files/package.json.html) 文件
267
- - ``router.js``:路由模块
268
- - ``server.js``:服务器主模块
269
- - ``config.js``:配置处理模块
268
+ 完整可运行的示例见仓库中的 [example](./example) 目录。
270
269
 
271
270
  ## TODO
272
271
 
@@ -17,7 +17,6 @@ const CONFIG = {
17
17
  "debug": false,
18
18
  "staticMaxage": 1800000,
19
19
  "staticHtmlFileMaxage": 0,
20
- "enableComboCache": true,
21
20
  "enableCron": false,
22
21
  "enableWorkerCron": false,
23
22
  "strictSSL": false,
package/dist/bin/watch.js CHANGED
@@ -44,8 +44,8 @@ const fs = require("fs");
44
44
  if (Number(code) !== 0) {
45
45
  const err = new Error(`子进程退出, Code: ${code}`);
46
46
  err.code = code;
47
- // TODO: 自动拉起来?
48
47
  console.error(err);
48
+ log("业务进程异常退出, watch 保持运行, 修复代码保存后将自动重启");
49
49
  }
50
50
  }).once("exit", ()=>{
51
51
  childProcess.removeAllListeners();
@@ -127,12 +127,28 @@ const fs = require("fs");
127
127
  log(e);
128
128
  }
129
129
  if (stats > 0) {
130
- // 传递主进程 SIGTERM
131
- process.on("SIGTERM", ()=>{
132
- if (childProcess && childProcess.connected) {
133
- childProcess.kill("SIGTERM");
134
- }
135
- process.exit(0);
130
+ // 传递退出信号: 通知业务进程优雅退出并等待其结束后自身再退出
131
+ // 注意不能用 childProcess.connected 判断( IPC 通道时恒为 false)
132
+ [
133
+ "SIGINT",
134
+ "SIGTERM"
135
+ ].forEach((signal)=>{
136
+ process.on(signal, ()=>{
137
+ if (!childProcess) {
138
+ process.exit(0);
139
+ }
140
+ const child = childProcess;
141
+ // 兜底强杀, 时长需覆盖业务的优雅退出(shutdownTimeout 默认 10s)
142
+ const timer = setTimeout(()=>{
143
+ child.kill("SIGKILL");
144
+ process.exit(0);
145
+ }, 30000);
146
+ child.once("exit", ()=>{
147
+ clearTimeout(timer);
148
+ process.exit(0);
149
+ });
150
+ child.kill("SIGTERM");
151
+ });
136
152
  });
137
153
  watch(chokidar, config, wait);
138
154
  start();
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "default", {
8
8
  return _default;
9
9
  }
10
10
  });
11
+ const _common = require("../components/common");
11
12
  const _utils = require("@x-drive/utils");
12
13
  const _config = require("../config");
13
14
  const serverPackge = require("../../package.json");
@@ -19,7 +20,7 @@ function _default() {
19
20
  const SERVER_MARK = `${serverPackge.name}@${serverPackge.version}`;
20
21
  // 业务启动时间
21
22
  // FIX ME : 服务器不是北京时间的时候这个数据跟实际启动的时间存在时差
22
- const MARK = `${CLIENT_MARK},${SERVER_MARK};Startup@${(0, _utils.date)(new Date(), "Y-m-d H:i:s")}`;
23
+ const MARK = (0, _common.asciiTobase64)(`${CLIENT_MARK};${SERVER_MARK};Startup@${(0, _utils.date)(new Date(), "Y-m-d H:i:s")}`);
23
24
  /**
24
25
  * 处理函数
25
26
  */ return async function handler(ctx, next) {
@@ -19,7 +19,6 @@ function _interop_require_default(obj) {
19
19
  }
20
20
  const cwd = process.cwd();
21
21
  /**内部中间件 */ const INTERNAL_MIDDLEWARE = {
22
- "combo": true,
23
22
  "bad-request": true,
24
23
  "fresh-filter": true,
25
24
  "handle-pre-dir": true,
package/dist/server.js CHANGED
@@ -202,6 +202,13 @@ app.poweredBy = false;
202
202
  // 10. 监听
203
203
  server = (0, _cluster.default)(app);
204
204
  // 11. 进程信号与异常处理
205
+ if (!config.isMaster) {
206
+ // master 异常退出(如被强杀)导致通道断开时, worker 自行优雅退出,
207
+ // 防止孤儿进程继续占用端口对外服务
208
+ process.on("disconnect", function() {
209
+ shutdown();
210
+ });
211
+ }
205
212
  process.on("SIGTERM", function() {
206
213
  shutdown();
207
214
  }).on("SIGINT", function() {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@x-9lab/xlab",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "9lab 服务端模块",
5
- "versionDesc": "v2: 移除全局挂载改为模块导出、显式生命周期与优雅退出、路由归一化",
5
+ "versionDesc": "watch 退出信号级联与 worker 孤儿防护;移除 combo 中间件残留",
6
6
  "scripts": {
7
7
  "dev": "swc src --copy-files --strip-leading-paths --config-file .swcrc -d dist -w",
8
8
  "compile": "swc src --copy-files --strip-leading-paths --config-file .swcrc -d dist",
@@ -48,4 +48,4 @@
48
48
  "type": "git",
49
49
  "url": "git+https://github.com/x-9lab/xlab.git"
50
50
  }
51
- }
51
+ }