@x-9lab/xlab 1.6.0 → 2.0.0

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.
Files changed (72) hide show
  1. package/@types/cluster.d.ts +15 -3
  2. package/@types/components/common/index.d.ts +1 -2
  3. package/@types/components/cron/index.d.ts +4 -4
  4. package/@types/components/log/index.d.ts +37 -2
  5. package/@types/config/index.d.ts +9 -5
  6. package/@types/custom.d.ts +25 -3
  7. package/@types/dot-file.d.ts +6 -0
  8. package/@types/global.d.ts +44 -54
  9. package/@types/index.d.ts +18 -0
  10. package/@types/init-env.d.ts +3 -1
  11. package/@types/middleware/handle-pre-dir.d.ts +1 -5
  12. package/@types/middleware/request-filter.d.ts +0 -1
  13. package/@types/middleware/service-mark.d.ts +1 -6
  14. package/@types/router.d.ts +25 -0
  15. package/@types/server.d.ts +28 -6
  16. package/MIGRATION.md +170 -0
  17. package/README.md +37 -17
  18. package/dist/@config/config.dev.js +7 -3
  19. package/dist/@config/config.js +7 -3
  20. package/dist/@config/config.sand.js +7 -3
  21. package/dist/bin/watch.js +13 -9
  22. package/dist/cluster.js +121 -44
  23. package/dist/components/assets/index.js +9 -5
  24. package/dist/components/cluster/index.js +17 -4
  25. package/dist/components/common/index.js +65 -45
  26. package/dist/components/cron/index.js +50 -27
  27. package/dist/components/header/index.js +32 -17
  28. package/dist/components/header/time.js +6 -2
  29. package/dist/components/index.js +1 -1
  30. package/dist/components/log/index.js +91 -87
  31. package/dist/components/mime/index.js +6 -2
  32. package/dist/components/return-code/index.js +33 -18
  33. package/dist/components/uuid/index.js +22 -13
  34. package/dist/config/getEnv.js +9 -5
  35. package/dist/config/index.js +98 -66
  36. package/dist/config/process-custom-config-files.js +26 -22
  37. package/dist/config/process-def-config-file.js +15 -11
  38. package/dist/custom.js +77 -28
  39. package/dist/default-x-config.js +9 -5
  40. package/dist/dot-file.js +42 -17
  41. package/dist/global.js +37 -31
  42. package/dist/index.js +100 -0
  43. package/dist/init-env.js +17 -10
  44. package/dist/middleware/@bin/html-filter.js +19 -7
  45. package/dist/middleware/bad-request.js +12 -8
  46. package/dist/middleware/compress.js +11 -7
  47. package/dist/middleware/cors.js +20 -7
  48. package/dist/middleware/fresh-filter.js +13 -7
  49. package/dist/middleware/handle-pre-dir.js +22 -17
  50. package/dist/middleware/request-filter.js +39 -25
  51. package/dist/middleware/service-mark.js +22 -25
  52. package/dist/middlewares.js +22 -19
  53. package/dist/router.js +174 -141
  54. package/dist/server.js +195 -93
  55. package/package.json +25 -29
  56. package/@types/business/utils/cookie/1.1.0/clean/index.d.ts +0 -3
  57. package/@types/business/utils/cookie/1.1.0/clean/js/index.d.ts +0 -2
  58. package/@types/components/cache/index.d.ts +0 -2
  59. package/@types/components/cache/lru.d.ts +0 -21
  60. package/@types/components/html-processor/index.d.ts +0 -9
  61. package/@types/components/injection/index.d.ts +0 -25
  62. package/@types/components/js-processor/index.d.ts +0 -5
  63. package/@types/components/md5/index.d.ts +0 -2
  64. package/@types/components/platform/index.d.ts +0 -21
  65. package/@types/components/proxy/index.d.ts +0 -26
  66. package/@types/components/querystring/index.d.ts +0 -25
  67. package/@types/components/redirect/index.d.ts +0 -11
  68. package/@types/components/request/helper.d.ts +0 -3
  69. package/@types/components/request/index.d.ts +0 -51
  70. package/@types/components/request/resolve-uri.d.ts +0 -6
  71. package/@types/components/version/index.d.ts +0 -26
  72. package/@types/env.d.ts +0 -1
package/README.md CHANGED
@@ -2,7 +2,7 @@ X-9lab 通用服务端
2
2
  =======
3
3
 
4
4
  ## 开发环境配置
5
- 1. 安装 [node](https://nodejs.org/) ,需要 10.0.0 以上版本
5
+ 1. 安装 [node](https://nodejs.org/) ,需要 20.0.0 以上版本
6
6
 
7
7
  ## 使用
8
8
  - 将 `@x-9lab/xlab` 加入到依赖中
@@ -56,30 +56,45 @@ X-9lab 通用服务端
56
56
  - 按照目录结构生成 api
57
57
  - 文件名是 `index` 的会被从 api 上先强行去掉
58
58
  - 默认都是 `get` 请求
59
+ - 文件名即方法:文件名是 `get/post/put/delete/patch/head/options/all` 之一时,从 api 路径上去掉并作为该接口的请求方法
59
60
  - 支持以下形式定义接口
60
- - 模块返回的是数组,则使用文件名做为方法名,并在 api 上去掉文件名
61
- - 非数组则文件当作正常的 api 地址
62
61
  - 模块返回为函数的则直接绑定为接口处理函数
63
- - 返回是对象则取对应的字段
64
- - `method` 接口类型,如 `get` 或 `post`
62
+ - 返回是对象则取对应的字段(推荐配合 `defineApi` 获得类型推导)
63
+ - `method` 接口类型,如 `get` 或 `post`,不指定时由文件名约定决定
64
+ - `api` 自定义接口地址
65
65
  - `middleware` 接口中间件
66
66
  - `handler` 接口处理函数
67
+ - `ignoreApiNameCheck` 是否忽略 `/api` 前缀检测
67
68
  - 特殊文件夹
68
69
  - 以 `@` 开头的文件夹, 该文件夹不会被当成接口文件夹,但可在正常的接口中作为普通模块使用
69
70
  - 以 `$` 开头的文件夹, 该文件夹中的文件会成为后续接口的通用中间件,可以用于某类型业务的统一处理,如后台某些接口的额外身份处理。为了防止滥用,该文件夹不会递归查找,也就是说不支持子文件夹的组织形式。
70
71
  - 整个 api 地址的每个父层都可以有独立的中间件文件,执行顺序会按照目录层级执行
71
72
  - 中间件文件夹内的文件只会按照文件名做简单排序,因此请特别注意执行顺序是否符合自己的预期,或采用带序号的文件名
72
- - 自定义逻辑,存放于 `custom` 目录,模块需要导出一个函数作为执行入口
73
+ - 自定义逻辑,存放于 `custom` 目录,模块导出一个函数作为执行入口(视为 `setup`),或导出 `{ setup, ready, shutdown }` 生命周期钩子对象
74
+ - `setup` 服务装配前执行,接收 `custom` 配置中声明的参数
75
+ - `ready` 服务启动完成(listen 成功)后执行
76
+ - `shutdown` 服务退出前执行,可用于释放连接等资源
73
77
  - 中间件,存放于 `middleware` 目录
74
78
  - 定时任务,存放于 `cron` 目录
75
79
  - 静态资源,默认存放在项目根目录下的 `public` 目录中
76
- ### 全局对象与函数
80
+ ### 模块 API
77
81
 
78
- #### 全局对象
79
- - `log` 全局日志对象
80
- - `masterLog` 只在 master 上输出的日志对象
82
+ v2 起框架 API 不再挂载到 global,统一从包导入(v1 升级请看 [MIGRATION.md](./MIGRATION.md)):
81
83
 
82
- #### 全局函数
84
+ ```js
85
+ const {
86
+ boot, shutdown // 生命周期
87
+ , app, getApp // Koa 应用实例
88
+ , getSysConfig, setSysConfig
89
+ , requireMod, requireModel, requireService
90
+ , getLogger, masterLog
91
+ , getXlabEnv // .xlab 环境数据
92
+ , defineApi // 路由定义帮助函数
93
+ } = require("@x-9lab/xlab");
94
+ ```
95
+
96
+ - `getLogger(cat)` 获取分类日志实例
97
+ - `masterLog(cat, type?, ...msg)` 只在 master 进程上输出的日志方法
83
98
  - `getApp` 获取应用实例对象
84
99
  ```ts
85
100
  /**
@@ -113,7 +128,9 @@ X-9lab 通用服务端
113
128
  */
114
129
  function setSysConfig(conf: XLab.IConfig): void;
115
130
  ```
116
- - `requireModel` 全局获取 model 的方法
131
+ - `getXlabEnv` 获取 `.xlab` 系列文件定义的环境数据
132
+ - `shutdown` 优雅退出:停止定时任务 → 等待在途请求 → 执行 `shutdown` 钩子 → 退出进程;收到 `SIGTERM` / `SIGINT` 时自动触发
133
+ - `requireModel` 获取 model 的方法
117
134
  该方法只是为获取 model 提供一个快捷方式,也可以通过正常的方式去 require
118
135
  - 存放路径 `business/@models`
119
136
  - 使用方式
@@ -121,7 +138,7 @@ X-9lab 通用服务端
121
138
  const { testModel } = requireModel("test");
122
139
  ```
123
140
  - 类型支持
124
- 由于 `requireModel` 是一个 `xlab` 的内置方法没有业务本身的 model 定义,因此需要业务方自行追加。出于管理方面的考虑,建议将所有的 model 定义放在一个文件中
141
+ 由于 `requireModel` 是一个 `xlab` 的内置方法没有业务本身的 model 定义,因此需要业务方自行追加(`XLab` 类型命名空间仍为全局,declaration merging 方式与 v1 一致)。出于管理方面的考虑,建议将所有的 model 定义放在一个文件中
125
142
  ```ts
126
143
  declare global {
127
144
  namespace XLab {
@@ -133,7 +150,7 @@ X-9lab 通用服务端
133
150
  }
134
151
  export { }
135
152
  ```
136
- - `requireService` 全局获取 service 的方法
153
+ - `requireService` 获取 service 的方法
137
154
  该方法只是为获取 service 提供一个快捷方式,也可以通过正常的方式去 require
138
155
  - 存放路径 `business/@services`
139
156
  - 使用方式
@@ -181,10 +198,11 @@ X-9lab 通用服务端
181
198
  |staticCros|`boolean`|false|是否允许静态资源跨域访问|
182
199
  |enableComboCache|`boolean`|true|是否开启 Combo 缓存|
183
200
  |enableCron|`boolean`|false|是否开启定时任务|
184
- |middleware|`Array<string | (string | Record<string, any>)[]>`|[]|开启的中间件列表。因不方便合并替换,v1.1.0 开始建议使用 `middlewares` 来配置 |
201
+ |enableWorkerCron|`boolean`|false|是否允许 worker 上也执行定时任务|
185
202
  |middlewares|`Record<string, MiddlewareConfig>`|{}|开启的中间件列表 |
186
203
  ||MiddlewareConfig||`index` 用于定义中间件位置,不提供将使用配置对象中的默认顺序<br/> `name` 中间件名称,不提供将使用配置对象的键名<br/>`config` 中间件配置|
187
- |custom|`string[]`||自定模块配置|
204
+ |custom|`(string | [string, any])[]`||自定模块配置,元组形式可传入参数|
205
+ |mark|`string`|name 配置|服务标识,用于 service-mark 中间件|
188
206
  |strictSSL|`boolean`||是否启用严格 ssl|
189
207
  |apis|`Record<string, string>`|{}|页端注入的 api 设置|
190
208
  |hasLo|`boolean`||本地是否存在本地开发配置文件|
@@ -197,7 +215,9 @@ X-9lab 通用服务端
197
215
  |pathReplaceRegExp|`string`||处理代理过来多余的地址层级路径替换判断正则|
198
216
  |routeMobile|`string`||移动端入口文件地址(旧版逻辑)|
199
217
  |launchRouter|`Record<string, string>`||不同端入口地址设置, 由 `@x-drive/launch-detect` 提供支持|
200
- |cron|`{def?: number;}`|{"def": 60}|定时任务设置|
218
+ |cron|`{def?: number;}`|{"def": 60}|定时任务设置,`def` 为默认间隔(秒)|
219
+ |crons|`Record<string, {delay?: number; enable?: boolean;}>`||按任务(文件名)的定时任务配置,`delay` 单位秒,优先级高于任务模块自身的 `getDelay()` / `enable()`|
220
+ |shutdownTimeout|`number`|10000|优雅退出时等待在途请求/worker 结束的超时时间(毫秒)|
201
221
  |injection|`string[]`|[]|注入参数列表|
202
222
  |indexPageCacheTime|`number`||首页缓存时间|
203
223
  |staticResourceCacheTime|`number`||静态资源缓存时间|
@@ -2,10 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.default = void 0;
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return _default;
9
+ }
10
+ });
6
11
  const CONFIG = {
7
12
  "304": false,
8
13
  "workers": 0
9
14
  };
10
- var _default = CONFIG;
11
- exports.default = _default;
15
+ const _default = CONFIG;
@@ -2,7 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.default = void 0;
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return _default;
9
+ }
10
+ });
6
11
  const CONFIG = {
7
12
  "host": "",
8
13
  "304": true,
@@ -19,5 +24,4 @@ const CONFIG = {
19
24
  "root": "public",
20
25
  "timezone": "Asia/Shanghai"
21
26
  };
22
- var _default = CONFIG;
23
- exports.default = _default;
27
+ const _default = CONFIG;
@@ -2,7 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.default = void 0;
5
+ Object.defineProperty(exports, "default", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return _default;
9
+ }
10
+ });
6
11
  const CONFIG = {};
7
- var _default = CONFIG;
8
- exports.default = _default;
12
+ const _default = CONFIG;
package/dist/bin/watch.js CHANGED
@@ -1,11 +1,14 @@
1
1
  "use strict";
2
2
  const XConfig = require("../default-x-config").default;
3
- const { date } = require("@x-drive/utils");
4
- const crossSpawn = require("cross-spawn");
5
- const colors = require("colors/safe");
3
+ const { spawn } = require("child_process");
4
+ const { date } = require("@x-drive/utils");
6
5
  const path = require("path");
7
6
  const fs = require("fs");
8
- /**输出内容名称 */ const X_LAB_STR = colors.bold(colors.cyan("\uD83D\uDEF8 XLab"));
7
+ /**终端着色,替代对 colors 包的依赖 */ const colors = {
8
+ "cyanBold": (str)=>`\x1b[1m\x1b[36m${str}\x1b[0m`,
9
+ "green": (str)=>`\x1b[32m${str}\x1b[0m`
10
+ };
11
+ /**输出内容名称 */ const X_LAB_STR = colors.cyanBold("🛸 XLab");
9
12
  /**
10
13
  * 子进程对象
11
14
  * @type child_process.ChildProcess
@@ -33,7 +36,7 @@ const fs = require("fs");
33
36
  }
34
37
  }
35
38
  /**启动 */ function start() {
36
- childProcess = crossSpawn("node", buildSpawnOptions(), {
39
+ childProcess = spawn(process.execPath, buildSpawnOptions(), {
37
40
  "stdio": "inherit"
38
41
  }).on("error", (err)=>{
39
42
  console.error(err);
@@ -90,7 +93,7 @@ const fs = require("fs");
90
93
  } else {
91
94
  if (initing) {
92
95
  initing = false;
93
- log("Watch \u6A21\u5F0F\u542F\u52A8\n");
96
+ log("Watch 模式启动\n");
94
97
  setTimeout(()=>{
95
98
  inited = true;
96
99
  }, wait);
@@ -118,6 +121,7 @@ const fs = require("fs");
118
121
  for(let i = 0; i < config.paths.length; i++){
119
122
  fs.statSync(config.paths[i]);
120
123
  stats += 1;
124
+ ;
121
125
  }
122
126
  } catch (e) {
123
127
  log(e);
@@ -133,14 +137,14 @@ const fs = require("fs");
133
137
  watch(chokidar, config, wait);
134
138
  start();
135
139
  } else {
136
- log("\u4E1A\u52A1\u81EA\u5B9A\u4E49\u76EE\u5F55\u4E0D\u5B58\u5728, watch \u6A21\u5F0F\u542F\u52A8\u5931\u8D25");
140
+ log("业务自定义目录不存在, watch 模式启动失败");
137
141
  }
138
142
  stats = null;
139
143
  } else {
140
- log("\u8BF7\u5C06 chokidar \u5B89\u88C5\u5230\u5F00\u53D1\u4F9D\u8D56\u4E2D\u4EE5\u542F\u7528 watch \u6A21\u5F0F");
144
+ log("请将 chokidar 安装到开发依赖中以启用 watch 模式");
141
145
  }
142
146
  } else {
143
- log("\u914D\u7F6E\u4E0D\u5B58\u5728\u6216 watch.enable \u4E3A false, watch \u6A21\u5F0F\u542F\u52A8\u5931\u8D25\n", config);
147
+ log("配置不存在或 watch.enable false, watch 模式启动失败\n", config);
144
148
  }
145
149
  }
146
150
  module.exports = setup;
package/dist/cluster.js CHANGED
@@ -2,53 +2,79 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.default = void 0;
6
- var clusterCom = _interopRequireWildcard(require("./components/cluster"));
7
- var _config = require("./config");
8
- var _cluster = _interopRequireDefault(require("cluster"));
9
- var _server = _interopRequireDefault(require("./server"));
10
- var _os = _interopRequireDefault(require("os"));
11
- function _interopRequireDefault(obj) {
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get default () {
13
+ return _default;
14
+ },
15
+ get shutdownWorkers () {
16
+ return shutdownWorkers;
17
+ }
18
+ });
19
+ const _cluster = /*#__PURE__*/ _interop_require_wildcard(require("./components/cluster"));
20
+ const _log = require("./components/log");
21
+ const _config = require("./config");
22
+ const _cluster1 = /*#__PURE__*/ _interop_require_default(require("cluster"));
23
+ const _os = /*#__PURE__*/ _interop_require_default(require("os"));
24
+ function _interop_require_default(obj) {
12
25
  return obj && obj.__esModule ? obj : {
13
26
  default: obj
14
27
  };
15
28
  }
16
- function _interopRequireWildcard(obj) {
17
- if (obj && obj.__esModule) {
18
- return obj;
19
- } else {
20
- var newObj = {};
21
- if (obj != null) {
22
- for(var key in obj){
23
- if (Object.prototype.hasOwnProperty.call(obj, key)) {
24
- var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};
25
- if (desc.get || desc.set) {
26
- Object.defineProperty(newObj, key, desc);
27
- } else {
28
- newObj[key] = obj[key];
29
- }
30
- }
31
- }
29
+ function _getRequireWildcardCache(nodeInterop) {
30
+ if (typeof WeakMap !== "function") return null;
31
+ var cacheBabelInterop = new WeakMap();
32
+ var cacheNodeInterop = new WeakMap();
33
+ return (_getRequireWildcardCache = function(nodeInterop) {
34
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
35
+ })(nodeInterop);
36
+ }
37
+ function _interop_require_wildcard(obj, nodeInterop) {
38
+ if (!nodeInterop && obj && obj.__esModule) return obj;
39
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") return {
40
+ default: obj
41
+ };
42
+ var cache = _getRequireWildcardCache(nodeInterop);
43
+ if (cache && cache.has(obj)) return cache.get(obj);
44
+ var newObj = {
45
+ __proto__: null
46
+ };
47
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
48
+ for(var key in obj){
49
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
50
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
51
+ if (desc && (desc.get || desc.set)) Object.defineProperty(newObj, key, desc);
52
+ else newObj[key] = obj[key];
32
53
  }
33
- newObj.default = obj;
34
- return newObj;
35
54
  }
55
+ newObj.default = obj;
56
+ if (cache) cache.set(obj, newObj);
57
+ return newObj;
36
58
  }
37
- const logger = log.getLogger("cluster");
59
+ const logger = _log.globalLog.getLogger("cluster");
38
60
  const CPUnum = _os.default.cpus().length;
39
- const config = (0, _config).get();
61
+ /**判定为快速失败的存活时间窗口(毫秒) */ const QUICK_DEATH_MS = 10 * 1000;
62
+ /**连续快速失败达到该次数后停止自动拉起 */ const MAX_QUICK_DEATHS = 5;
63
+ /**worker 启动时间记录 */ const FORK_AT = new Map();
64
+ /**连续快速失败计数 */ var quickDeaths = 0;
65
+ /**是否正在退出流程中 */ var stopping = false;
40
66
  /**
41
67
  * 消息处理函数
42
68
  * @param msg 消息配置对象
43
69
  */ function masterMessageHandler(msg) {
44
70
  if (msg && msg.cmd) {
45
- let handler = clusterCom.get(msg.cmd);
71
+ let handler = _cluster.get(msg.cmd);
46
72
  if (handler) {
47
73
  let args = msg.args || [];
48
74
  args.push(msg.returnData);
49
75
  let re = handler.apply(handler, args);
50
76
  if (msg.wid) {
51
- let worker = _cluster.default.workers[msg.wid];
77
+ let worker = _cluster1.default.workers[msg.wid];
52
78
  if (worker) {
53
79
  worker.send({
54
80
  "cmd": msg.cmd,
@@ -62,7 +88,18 @@ const config = (0, _config).get();
62
88
  }
63
89
  }
64
90
  }
65
- /**尝试以 cluster 模式启动服务 */ function start() {
91
+ /**fork 一个 worker 并记录启动时间 */ function forkWorker() {
92
+ const worker = _cluster1.default.fork();
93
+ FORK_AT.set(worker.id, Date.now());
94
+ }
95
+ /**
96
+ * 启动服务监听
97
+
98
+ * master 且配置了 workers 时 fork 集群, 否则当前进程直接 listen
99
+ * @param app Koa 实例
100
+ * @return 直接监听时返回 http.Server, master fork 模式下无返回
101
+ */ function start(app) {
102
+ const config = (0, _config.get)();
66
103
  var server;
67
104
  var serverListenConf = {
68
105
  "port": config.port
@@ -75,26 +112,66 @@ const config = (0, _config).get();
75
112
  // 小于使用数则取一半
76
113
  let num = CPUnum < config.workers ? Math.ceil(CPUnum / 2) : config.workers;
77
114
  for(var i = 0; i < num; i++){
78
- _cluster.default.fork();
115
+ forkWorker();
79
116
  }
80
- // if(!config.isProd){
81
- _cluster.default.on("listening", function(worker, address) {
82
- masterLog("cluster", "info", " Worker ", worker.process.pid, " online, Address: ", address.address, ":", address.port);
117
+ _cluster1.default.on("listening", function(worker, address) {
118
+ logger.info("\tWorker ", worker.process.pid, " online, Address: ", address.address, ":", address.port);
83
119
  });
84
- _cluster.default.on("message", masterMessageHandler);
85
- // }
86
- _cluster.default.on("exit", function(worker) {
87
- logger.warn("Worker " + worker.process.pid + " is dead!");
88
- _cluster.default.fork();
120
+ _cluster1.default.on("message", masterMessageHandler);
121
+ _cluster1.default.on("exit", function(worker) {
122
+ const bornAt = FORK_AT.get(worker.id);
123
+ FORK_AT.delete(worker.id);
124
+ if (stopping) {
125
+ return;
126
+ }
127
+ const uptime = Date.now() - (bornAt || 0);
128
+ if (bornAt && uptime < QUICK_DEATH_MS) {
129
+ quickDeaths += 1;
130
+ } else {
131
+ quickDeaths = 0;
132
+ }
133
+ if (quickDeaths >= MAX_QUICK_DEATHS) {
134
+ logger.error(`Worker ${worker.process.pid} is dead! 连续 ${quickDeaths} 次快速退出, 停止自动拉起, 请排查业务异常`);
135
+ return;
136
+ }
137
+ logger.warn(`Worker ${worker.process.pid} is dead! Reforking.`);
138
+ forkWorker();
89
139
  });
90
140
  } else {
91
- server = _server.default.listen(serverListenConf);
141
+ server = app.listen(serverListenConf);
92
142
  }
93
- masterLog("cluster", "info", "[%s] online,listening on %s port %d", config.env, config.ip || "localhost", config.port);
143
+ logger.info("[%s] online,listening on %s port %d", config.env, config.ip || "localhost", config.port);
94
144
  } else {
95
- server = _server.default.listen(serverListenConf);
145
+ server = app.listen(serverListenConf);
96
146
  }
97
147
  return server;
98
148
  }
99
- var _default = start;
100
- exports.default = _default;
149
+ const _default = start;
150
+ /**
151
+ * 通知全部 worker 退出并等待其结束
152
+ * @param timeout 等待超时(毫秒), 超时后不再等待
153
+ */ function shutdownWorkers(timeout = 10 * 1000) {
154
+ stopping = true;
155
+ return new Promise(function(resolve) {
156
+ const workers = Object.values(_cluster1.default.workers || {}).filter(Boolean);
157
+ if (!workers.length) {
158
+ resolve();
159
+ return;
160
+ }
161
+ var alive = workers.length;
162
+ const timer = setTimeout(function() {
163
+ logger.warn(`等待 worker 退出超时(${timeout}ms)`);
164
+ resolve();
165
+ }, timeout);
166
+ workers.forEach(function(worker) {
167
+ worker.once("exit", function() {
168
+ alive -= 1;
169
+ if (alive === 0) {
170
+ clearTimeout(timer);
171
+ resolve();
172
+ }
173
+ });
174
+ worker.process.kill("SIGTERM");
175
+ });
176
+ });
177
+ }
@@ -2,10 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.get = void 0;
6
- var _path = _interopRequireDefault(require("path"));
7
- var _fs = _interopRequireDefault(require("fs"));
8
- function _interopRequireDefault(obj) {
5
+ Object.defineProperty(exports, "get", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return get;
9
+ }
10
+ });
11
+ const _path = /*#__PURE__*/ _interop_require_default(require("path"));
12
+ const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
13
+ function _interop_require_default(obj) {
9
14
  return obj && obj.__esModule ? obj : {
10
15
  default: obj
11
16
  };
@@ -26,4 +31,3 @@ try {
26
31
  */ function get(name) {
27
32
  return ASSETS[name] || null;
28
33
  }
29
- exports.get = get;
@@ -2,7 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- exports.del = exports.add = exports.get = void 0;
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get add () {
13
+ return add;
14
+ },
15
+ get del () {
16
+ return del;
17
+ },
18
+ get get () {
19
+ return get;
20
+ }
21
+ });
6
22
  /**
7
23
  * 消息注册存储对象
8
24
  */ const MSG_HANDLERS = {};
@@ -28,6 +44,3 @@ exports.del = exports.add = exports.get = void 0;
28
44
  */ function del(cmd) {
29
45
  delete MSG_HANDLERS[cmd];
30
46
  }
31
- exports.get = get;
32
- exports.add = add;
33
- exports.del = del;
@@ -2,38 +2,70 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "sleep", {
6
- enumerable: true,
7
- get: function() {
8
- return _utils.sleep;
9
- }
10
- });
11
- Object.defineProperty(exports, "labelReplace", {
12
- enumerable: true,
13
- get: function() {
14
- return _utils.labelReplace;
15
- }
16
- });
17
- Object.defineProperty(exports, "fix0", {
18
- enumerable: true,
19
- get: function() {
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get asciiTobase64 () {
13
+ return asciiTobase64;
14
+ },
15
+ get base64Toascii () {
16
+ return base64Toascii;
17
+ },
18
+ get checkFileStat () {
19
+ return checkFileStat;
20
+ },
21
+ get fix0 () {
20
22
  return _utils.fix0;
21
- }
22
- });
23
- Object.defineProperty(exports, "numberFormat", {
24
- enumerable: true,
25
- get: function() {
23
+ },
24
+ get formatJson () {
25
+ return formatJson;
26
+ },
27
+ get getMD5 () {
28
+ return getMD5;
29
+ },
30
+ get getRealDefaultMod () {
31
+ return getRealDefaultMod;
32
+ },
33
+ get labelReplace () {
34
+ return _utils.labelReplace;
35
+ },
36
+ get md5 () {
37
+ return md5;
38
+ },
39
+ get numberFormat () {
26
40
  return _utils.numberFormat;
41
+ },
42
+ get object2Array () {
43
+ return object2Array;
44
+ },
45
+ get params () {
46
+ return params;
47
+ },
48
+ get responseResult () {
49
+ return responseResult;
50
+ },
51
+ get sleep () {
52
+ return _utils.sleep;
53
+ },
54
+ get toJsonp () {
55
+ return toJsonp;
56
+ },
57
+ get walk () {
58
+ return walk;
27
59
  }
28
60
  });
29
- exports.getRealDefaultMod = exports.checkFileStat = exports.walk = exports.toJsonp = exports.formatJson = exports.object2Array = exports.md5 = exports.getMD5 = exports.responseResult = exports.params = exports.base64Toascii = exports.asciiTobase64 = void 0;
30
- var _utils = require("@x-drive/utils");
31
- var _returnCode = require("../return-code");
32
- var _querystring = _interopRequireDefault(require("querystring"));
33
- var _crypto = _interopRequireDefault(require("crypto"));
34
- var _path = _interopRequireDefault(require("path"));
35
- var _fs = _interopRequireDefault(require("fs"));
36
- function _interopRequireDefault(obj) {
61
+ const _utils = require("@x-drive/utils");
62
+ const _returncode = require("../return-code");
63
+ const _log = require("../log");
64
+ const _querystring = /*#__PURE__*/ _interop_require_default(require("querystring"));
65
+ const _crypto = /*#__PURE__*/ _interop_require_default(require("crypto"));
66
+ const _path = /*#__PURE__*/ _interop_require_default(require("path"));
67
+ const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
68
+ function _interop_require_default(obj) {
37
69
  return obj && obj.__esModule ? obj : {
38
70
  default: obj
39
71
  };
@@ -41,7 +73,7 @@ function _interopRequireDefault(obj) {
41
73
  var logger;
42
74
  function checkLogger() {
43
75
  if (!logger) {
44
- logger = log.getLogger("common");
76
+ logger = _log.globalLog.getLogger("common");
45
77
  }
46
78
  return logger;
47
79
  }
@@ -84,7 +116,7 @@ function checkLogger() {
84
116
  * @param msg 返回的提示性信息
85
117
  * @return 数据对象
86
118
  */ function responseResult(status, result, msg) {
87
- var code = (0, _utils).isObject(status) ? status : (0, _returnCode).getReturnCode(status);
119
+ var code = (0, _utils.isObject)(status) ? status : (0, _returncode.getReturnCode)(status);
88
120
  var dat = {
89
121
  "success": code.errorcode === 0,
90
122
  "code": code.errorcode,
@@ -103,9 +135,9 @@ function checkLogger() {
103
135
  return _crypto.default.createHash("md5").update(JSON.stringify(conditions), "utf8").digest("hex");
104
136
  }
105
137
  /**将一个输入字符串转为 md5 */ function md5(str) {
106
- var md51 = _crypto.default.createHash("md5");
107
- md51.update(str);
108
- return md51.digest("hex");
138
+ var md5 = _crypto.default.createHash("md5");
139
+ md5.update(str);
140
+ return md5.digest("hex");
109
141
  }
110
142
  /**
111
143
  * 对象值转化为数组
@@ -186,15 +218,3 @@ function checkLogger() {
186
218
  }
187
219
  return mod;
188
220
  }
189
- exports.asciiTobase64 = asciiTobase64;
190
- exports.base64Toascii = base64Toascii;
191
- exports.params = params;
192
- exports.responseResult = responseResult;
193
- exports.getMD5 = getMD5;
194
- exports.md5 = md5;
195
- exports.object2Array = object2Array;
196
- exports.formatJson = formatJson;
197
- exports.toJsonp = toJsonp;
198
- exports.walk = walk;
199
- exports.checkFileStat = checkFileStat;
200
- exports.getRealDefaultMod = getRealDefaultMod;