@midwayjs/bootstrap 3.8.0 → 3.9.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.
- package/dist/bootstrap.d.ts +8 -7
- package/dist/bootstrap.js +34 -17
- package/dist/index.d.ts +6 -1
- package/dist/index.js +24 -2
- package/dist/interface.d.ts +46 -0
- package/dist/interface.js +3 -0
- package/dist/manager/base.d.ts +46 -0
- package/dist/manager/base.js +182 -0
- package/dist/manager/cp.d.ts +17 -0
- package/dist/manager/cp.js +58 -0
- package/dist/manager/thread.d.ts +18 -0
- package/dist/manager/thread.js +63 -0
- package/dist/sticky.d.ts +3 -0
- package/dist/sticky.js +143 -0
- package/dist/util.d.ts +4 -0
- package/dist/util.js +63 -0
- package/package.json +6 -7
package/dist/bootstrap.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { IMidwayBootstrapOptions, IMidwayContainer } from '@midwayjs/core';
|
|
2
|
-
|
|
2
|
+
import { IMidwayLogger } from '@midwayjs/logger';
|
|
3
3
|
export declare class BootstrapStarter {
|
|
4
4
|
protected appDir: string;
|
|
5
5
|
protected baseDir: string;
|
|
6
6
|
protected globalOptions: Partial<IMidwayBootstrapOptions>;
|
|
7
7
|
protected globalConfig: any;
|
|
8
8
|
private applicationContext;
|
|
9
|
-
|
|
9
|
+
private eventBus;
|
|
10
|
+
configure(options?: IMidwayBootstrapOptions): this;
|
|
10
11
|
init(): Promise<IMidwayContainer>;
|
|
11
12
|
run(): Promise<void>;
|
|
12
13
|
stop(): Promise<void>;
|
|
@@ -14,16 +15,16 @@ export declare class BootstrapStarter {
|
|
|
14
15
|
protected getBaseDir(): string;
|
|
15
16
|
}
|
|
16
17
|
export declare class Bootstrap {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
protected static starter: BootstrapStarter;
|
|
19
|
+
protected static logger: IMidwayLogger;
|
|
20
|
+
protected static configured: boolean;
|
|
20
21
|
/**
|
|
21
22
|
* set global configuration for midway
|
|
22
23
|
* @param configuration
|
|
23
24
|
*/
|
|
24
25
|
static configure(configuration?: IMidwayBootstrapOptions): typeof Bootstrap;
|
|
25
|
-
|
|
26
|
-
static run(): Promise<
|
|
26
|
+
static getStarter(): BootstrapStarter;
|
|
27
|
+
static run(): Promise<IMidwayContainer>;
|
|
27
28
|
static stop(): Promise<void>;
|
|
28
29
|
static reset(): void;
|
|
29
30
|
/**
|
package/dist/bootstrap.js
CHANGED
|
@@ -1,45 +1,61 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Bootstrap = exports.BootstrapStarter =
|
|
3
|
+
exports.Bootstrap = exports.BootstrapStarter = void 0;
|
|
4
4
|
const core_1 = require("@midwayjs/core");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const logger_1 = require("@midwayjs/logger");
|
|
7
7
|
const async_hooks_context_manager_1 = require("@midwayjs/async-hooks-context-manager");
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return false;
|
|
12
|
-
}
|
|
13
|
-
// eslint-disable-next-line node/no-deprecated-api
|
|
14
|
-
return TS_MODE_PROCESS_FLAG === 'true' || !!require.extensions['.ts'];
|
|
15
|
-
}
|
|
16
|
-
exports.isTypeScriptEnvironment = isTypeScriptEnvironment;
|
|
8
|
+
const util_1 = require("./util");
|
|
9
|
+
const event_bus_1 = require("@midwayjs/event-bus");
|
|
10
|
+
const sticky_1 = require("./sticky");
|
|
17
11
|
class BootstrapStarter {
|
|
18
12
|
constructor() {
|
|
19
13
|
this.globalOptions = {};
|
|
20
14
|
}
|
|
21
|
-
configure(options) {
|
|
15
|
+
configure(options = {}) {
|
|
22
16
|
this.globalOptions = options;
|
|
23
17
|
return this;
|
|
24
18
|
}
|
|
25
19
|
async init() {
|
|
26
|
-
this.appDir = this.globalOptions.appDir
|
|
27
|
-
|
|
20
|
+
this.appDir = this.globalOptions.appDir =
|
|
21
|
+
this.globalOptions.appDir || process.cwd();
|
|
22
|
+
this.baseDir = this.globalOptions.baseDir = this.getBaseDir();
|
|
23
|
+
if (process.env['MIDWAY_FORK_MODE']) {
|
|
24
|
+
if (process.env['MIDWAY_FORK_MODE'] === 'cluster') {
|
|
25
|
+
this.eventBus = new event_bus_1.ChildProcessEventBus({
|
|
26
|
+
isWorker: true,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else if (process.env['MIDWAY_FORK_MODE'] === 'thread') {
|
|
30
|
+
this.eventBus = new event_bus_1.ThreadEventBus({
|
|
31
|
+
isWorker: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
28
35
|
this.applicationContext = await (0, core_1.initializeGlobalApplicationContext)({
|
|
29
|
-
...this.globalOptions,
|
|
30
|
-
appDir: this.appDir,
|
|
31
|
-
baseDir: this.baseDir,
|
|
32
36
|
asyncContextManager: (0, async_hooks_context_manager_1.createContextManager)(),
|
|
37
|
+
...this.globalOptions,
|
|
33
38
|
});
|
|
34
39
|
return this.applicationContext;
|
|
35
40
|
}
|
|
36
41
|
async run() {
|
|
37
42
|
this.applicationContext = await this.init();
|
|
43
|
+
if (this.eventBus) {
|
|
44
|
+
await this.eventBus.start();
|
|
45
|
+
if (process.env['MIDWAY_STICKY_MODE'] === 'true') {
|
|
46
|
+
const applicationManager = this.applicationContext.get(core_1.MidwayApplicationManager);
|
|
47
|
+
const io = applicationManager.getApplication('socketIO');
|
|
48
|
+
(0, sticky_1.setupWorker)(io);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
38
51
|
}
|
|
39
52
|
async stop() {
|
|
40
53
|
if (this.applicationContext) {
|
|
41
54
|
await (0, core_1.destroyGlobalApplicationContext)(this.applicationContext);
|
|
42
55
|
}
|
|
56
|
+
if (this.eventBus) {
|
|
57
|
+
await this.eventBus.stop();
|
|
58
|
+
}
|
|
43
59
|
}
|
|
44
60
|
getApplicationContext() {
|
|
45
61
|
return this.applicationContext;
|
|
@@ -48,7 +64,7 @@ class BootstrapStarter {
|
|
|
48
64
|
if (this.globalOptions.baseDir) {
|
|
49
65
|
return this.globalOptions.baseDir;
|
|
50
66
|
}
|
|
51
|
-
if (isTypeScriptEnvironment()) {
|
|
67
|
+
if ((0, util_1.isTypeScriptEnvironment)()) {
|
|
52
68
|
return (0, path_1.join)(this.appDir, 'src');
|
|
53
69
|
}
|
|
54
70
|
else {
|
|
@@ -113,6 +129,7 @@ class Bootstrap {
|
|
|
113
129
|
.then(() => {
|
|
114
130
|
this.logger.info('[midway:bootstrap] current app started');
|
|
115
131
|
global['MIDWAY_BOOTSTRAP_APP_READY'] = true;
|
|
132
|
+
return this.getApplicationContext();
|
|
116
133
|
})
|
|
117
134
|
.catch(err => {
|
|
118
135
|
this.logger.error(err);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './interface';
|
|
2
|
+
export { isTypeScriptEnvironment } from './util';
|
|
3
|
+
export { Bootstrap, BootstrapStarter } from './bootstrap';
|
|
4
|
+
export { ClusterManager } from './manager/cp';
|
|
5
|
+
export { AbstractForkManager } from './manager/base';
|
|
6
|
+
export { setupStickyMaster } from './sticky';
|
|
2
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,30 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BootstrapStarter = exports.Bootstrap = exports.isTypeScriptEnvironment = void 0;
|
|
17
|
+
exports.setupStickyMaster = exports.AbstractForkManager = exports.ClusterManager = exports.BootstrapStarter = exports.Bootstrap = exports.isTypeScriptEnvironment = void 0;
|
|
18
|
+
__exportStar(require("./interface"), exports);
|
|
19
|
+
var util_1 = require("./util");
|
|
20
|
+
Object.defineProperty(exports, "isTypeScriptEnvironment", { enumerable: true, get: function () { return util_1.isTypeScriptEnvironment; } });
|
|
4
21
|
var bootstrap_1 = require("./bootstrap");
|
|
5
|
-
Object.defineProperty(exports, "isTypeScriptEnvironment", { enumerable: true, get: function () { return bootstrap_1.isTypeScriptEnvironment; } });
|
|
6
22
|
Object.defineProperty(exports, "Bootstrap", { enumerable: true, get: function () { return bootstrap_1.Bootstrap; } });
|
|
7
23
|
Object.defineProperty(exports, "BootstrapStarter", { enumerable: true, get: function () { return bootstrap_1.BootstrapStarter; } });
|
|
24
|
+
var cp_1 = require("./manager/cp");
|
|
25
|
+
Object.defineProperty(exports, "ClusterManager", { enumerable: true, get: function () { return cp_1.ClusterManager; } });
|
|
26
|
+
var base_1 = require("./manager/base");
|
|
27
|
+
Object.defineProperty(exports, "AbstractForkManager", { enumerable: true, get: function () { return base_1.AbstractForkManager; } });
|
|
28
|
+
var sticky_1 = require("./sticky");
|
|
29
|
+
Object.defineProperty(exports, "setupStickyMaster", { enumerable: true, get: function () { return sticky_1.setupStickyMaster; } });
|
|
8
30
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
import type { IMidwayLogger } from '@midwayjs/logger';
|
|
5
|
+
import { ClusterSettings } from 'cluster';
|
|
6
|
+
import { WorkerOptions } from 'worker_threads';
|
|
7
|
+
export interface ForkOptions {
|
|
8
|
+
exec?: string;
|
|
9
|
+
/**
|
|
10
|
+
* worker num, default is `os.cpus().length`
|
|
11
|
+
*/
|
|
12
|
+
count?: number;
|
|
13
|
+
/**
|
|
14
|
+
* refork when disconect and unexpected exit, default is `true`
|
|
15
|
+
*/
|
|
16
|
+
refork?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* restart limit, default is `60`
|
|
19
|
+
*/
|
|
20
|
+
limit?: number;
|
|
21
|
+
duration?: number;
|
|
22
|
+
logger?: IMidwayLogger | Console;
|
|
23
|
+
/**
|
|
24
|
+
* Some environments set to worker
|
|
25
|
+
*/
|
|
26
|
+
env?: Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* Worker init Timeout, default is 30s,
|
|
29
|
+
*/
|
|
30
|
+
workerInitTimeout?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface IForkManager<T> {
|
|
33
|
+
start(): any;
|
|
34
|
+
close(): any;
|
|
35
|
+
hasWorker(workerId: string): boolean;
|
|
36
|
+
getWorker(workerId: string): T;
|
|
37
|
+
getWorkerIds(): string[];
|
|
38
|
+
isWorkerDead(worker: T): boolean;
|
|
39
|
+
isPrimary(): boolean;
|
|
40
|
+
}
|
|
41
|
+
export declare type ClusterOptions = ForkOptions & ClusterSettings & {
|
|
42
|
+
sticky?: boolean;
|
|
43
|
+
stickyLoadBalancingMethod?: 'random' | 'round-robin' | 'least-connection';
|
|
44
|
+
};
|
|
45
|
+
export declare type ThreadOptions = ForkOptions & WorkerOptions;
|
|
46
|
+
//# sourceMappingURL=interface.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ForkOptions } from '../interface';
|
|
2
|
+
import type { IEventBus, EventBusOptions } from '@midwayjs/event-bus';
|
|
3
|
+
export declare abstract class AbstractForkManager<T, ClusterOptions extends ForkOptions> {
|
|
4
|
+
readonly options: ClusterOptions;
|
|
5
|
+
private reforks;
|
|
6
|
+
private disconnectCount;
|
|
7
|
+
private unexpectedCount;
|
|
8
|
+
private disconnects;
|
|
9
|
+
private hub;
|
|
10
|
+
protected workers: Map<string, T>;
|
|
11
|
+
protected eventBus: IEventBus<T>;
|
|
12
|
+
private isClosing;
|
|
13
|
+
protected constructor(options: ClusterOptions);
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
protected tryToRefork(oldWorker: T): void;
|
|
16
|
+
/**
|
|
17
|
+
* allow refork
|
|
18
|
+
*/
|
|
19
|
+
protected allowRefork(): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* uncaughtException default handler
|
|
22
|
+
*/
|
|
23
|
+
protected onerror(err: any): void;
|
|
24
|
+
/**
|
|
25
|
+
* unexpectedExit default handler
|
|
26
|
+
*/
|
|
27
|
+
protected onUnexpected(worker: T, code: any, signal: any): void;
|
|
28
|
+
/**
|
|
29
|
+
* reachReforkLimit default handler
|
|
30
|
+
*/
|
|
31
|
+
protected onReachReforkLimit(): void;
|
|
32
|
+
protected killWorker(worker: any, timeout: any): Promise<void>;
|
|
33
|
+
close(timeout?: number): Promise<void>;
|
|
34
|
+
hasWorker(workerId: string): boolean;
|
|
35
|
+
getWorker(workerId: string): T;
|
|
36
|
+
getWorkerIds(): string[];
|
|
37
|
+
abstract createWorker(oldWorker?: T): T;
|
|
38
|
+
abstract bindWorkerDisconnect(listener: (worker: T) => void): void;
|
|
39
|
+
abstract bindWorkerExit(listener: (worker: T, code: any, signal: any) => void): void;
|
|
40
|
+
abstract getWorkerId(worker: T): string;
|
|
41
|
+
abstract isWorkerDead(worker: T): boolean;
|
|
42
|
+
abstract closeWorker(worker: T): any;
|
|
43
|
+
abstract createEventBus(eventBusOptions: EventBusOptions): IEventBus<T>;
|
|
44
|
+
abstract isPrimary(): boolean;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AbstractForkManager = void 0;
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const util = require("util");
|
|
6
|
+
const util_1 = require("../util");
|
|
7
|
+
const events_1 = require("events");
|
|
8
|
+
const util_2 = require("util");
|
|
9
|
+
const debug = (0, util_2.debuglog)('midway:bootstrap');
|
|
10
|
+
class AbstractForkManager {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
this.reforks = [];
|
|
14
|
+
this.disconnectCount = 0;
|
|
15
|
+
this.unexpectedCount = 0;
|
|
16
|
+
this.disconnects = {};
|
|
17
|
+
this.hub = new events_1.EventEmitter();
|
|
18
|
+
this.workers = new Map();
|
|
19
|
+
this.isClosing = false;
|
|
20
|
+
options.count = options.count || os.cpus().length - 1;
|
|
21
|
+
options.refork = options.refork !== false;
|
|
22
|
+
options.limit = options.limit || 60;
|
|
23
|
+
options.duration = options.duration || 60000; // 1 min
|
|
24
|
+
options.logger = options.logger || console;
|
|
25
|
+
options.workerInitTimeout = options.workerInitTimeout || 30000;
|
|
26
|
+
this.eventBus = this.createEventBus({
|
|
27
|
+
initTimeout: options.workerInitTimeout,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async start() {
|
|
31
|
+
debug('Start manager with options: %j', this.options);
|
|
32
|
+
this.bindWorkerDisconnect(worker => {
|
|
33
|
+
debug(' - worker(%s): trigger event = disconnect', this.getWorkerId(worker));
|
|
34
|
+
const log = this.options.logger[worker['disableRefork'] ? 'info' : 'error'];
|
|
35
|
+
this.disconnectCount++;
|
|
36
|
+
const isDead = this.isWorkerDead(worker);
|
|
37
|
+
if (isDead) {
|
|
38
|
+
debug(' - worker(%s): worker is dead', this.getWorkerId(worker));
|
|
39
|
+
// worker has terminated before disconnect
|
|
40
|
+
this.options.logger.info("[%s] [bootstrap:master:%s] don't fork, because worker:%s exit event emit before disconnect", (0, util_1.logDate)(), process.pid, this.getWorkerId(worker));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (worker['disableRefork']) {
|
|
44
|
+
debug(' - worker(%s): worker is disableRefork(maybe terminated by master)', this.getWorkerId(worker));
|
|
45
|
+
// worker has terminated by master
|
|
46
|
+
log("[%s] [bootstrap:master:%s] don't fork, because worker:%s will be kill soon", (0, util_1.logDate)(), process.pid, this.getWorkerId(worker));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.disconnects[this.getWorkerId(worker)] = (0, util_1.logDate)();
|
|
50
|
+
this.tryToRefork(worker);
|
|
51
|
+
});
|
|
52
|
+
this.bindWorkerExit((worker, code, signal) => {
|
|
53
|
+
debug(' - worker(%s): trigger event = exit', this.getWorkerId(worker));
|
|
54
|
+
// remove worker
|
|
55
|
+
this.workers.delete(this.getWorkerId(worker));
|
|
56
|
+
if (worker['disableRefork']) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const isExpected = !!this.disconnects[this.getWorkerId(worker)];
|
|
60
|
+
debug(' - worker(%s): isExpected=%s', this.getWorkerId(worker), isExpected);
|
|
61
|
+
if (isExpected) {
|
|
62
|
+
delete this.disconnects[this.getWorkerId(worker)];
|
|
63
|
+
// worker disconnect first, exit expected
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
debug(' - worker(%s): isWorkerDead=%s', this.getWorkerId(worker), this.isWorkerDead(worker));
|
|
67
|
+
if (this.isWorkerDead(worker)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
debug(' - worker(%s): unexpectedCount will add');
|
|
71
|
+
this.unexpectedCount++;
|
|
72
|
+
this.tryToRefork(worker);
|
|
73
|
+
this.onUnexpected(worker, code, signal);
|
|
74
|
+
});
|
|
75
|
+
this.hub.on('reachReforkLimit', this.onReachReforkLimit.bind(this));
|
|
76
|
+
// defer to set the listeners
|
|
77
|
+
// so you can listen this by your own
|
|
78
|
+
setImmediate(() => {
|
|
79
|
+
if (process.listeners('uncaughtException').length === 0) {
|
|
80
|
+
process.on('uncaughtException', this.onerror.bind(this));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
for (let i = 0; i < this.options.count; i++) {
|
|
84
|
+
const w = this.createWorker();
|
|
85
|
+
debug(' - worker(%s) created', this.getWorkerId(w));
|
|
86
|
+
this.eventBus.addWorker(w);
|
|
87
|
+
this.workers.set(this.getWorkerId(w), w);
|
|
88
|
+
}
|
|
89
|
+
await this.eventBus.start();
|
|
90
|
+
}
|
|
91
|
+
tryToRefork(oldWorker) {
|
|
92
|
+
if (this.allowRefork()) {
|
|
93
|
+
debug(' - worker(%s): allow refork and will fork new', this.getWorkerId(oldWorker));
|
|
94
|
+
const newWorker = this.createWorker(oldWorker);
|
|
95
|
+
this.workers.set(this.getWorkerId(newWorker), newWorker);
|
|
96
|
+
this.options.logger.info('[%s] [bootstrap:master:%s] new worker:%s fork (state: %s)', (0, util_1.logDate)(), process.pid, this.getWorkerId(newWorker), newWorker['state']);
|
|
97
|
+
this.eventBus.addWorker(newWorker);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
debug(' - worker(%s): forbidden refork and will stop', this.getWorkerId(oldWorker));
|
|
101
|
+
this.options.logger.info("[%s] [bootstrap:master:%s] don't fork new work (refork: %s)", (0, util_1.logDate)(), process.pid, this.options.refork);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* allow refork
|
|
106
|
+
*/
|
|
107
|
+
allowRefork() {
|
|
108
|
+
if (!this.options.refork || this.isClosing) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
const times = this.reforks.push(Date.now());
|
|
112
|
+
if (times > this.options.limit) {
|
|
113
|
+
this.reforks.shift();
|
|
114
|
+
}
|
|
115
|
+
const span = this.reforks[this.reforks.length - 1] - this.reforks[0];
|
|
116
|
+
const canFork = this.reforks.length < this.options.limit || span > this.options.duration;
|
|
117
|
+
if (!canFork) {
|
|
118
|
+
this.hub.emit('reachReforkLimit');
|
|
119
|
+
}
|
|
120
|
+
return canFork;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* uncaughtException default handler
|
|
124
|
+
*/
|
|
125
|
+
onerror(err) {
|
|
126
|
+
if (!err) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.options.logger.error('[%s] [bootstrap:master:%s] master uncaughtException: %s', (0, util_1.logDate)(), process.pid, err.stack);
|
|
130
|
+
this.options.logger.error(err);
|
|
131
|
+
this.options.logger.error('(total %d disconnect, %d unexpected exit)', this.disconnectCount, this.unexpectedCount);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* unexpectedExit default handler
|
|
135
|
+
*/
|
|
136
|
+
onUnexpected(worker, code, signal) {
|
|
137
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
138
|
+
const propertyName = worker.hasOwnProperty('exitedAfterDisconnect')
|
|
139
|
+
? 'exitedAfterDisconnect'
|
|
140
|
+
: 'suicide';
|
|
141
|
+
const err = new Error(util.format('worker:%s died unexpected (code: %s, signal: %s, %s: %s, state: %s)', this.getWorkerId(worker), code, signal, propertyName, worker[propertyName], worker['state']));
|
|
142
|
+
err.name = 'WorkerDiedUnexpectedError';
|
|
143
|
+
this.options.logger.error('[%s] [bootstrap:master:%s] (total %d disconnect, %d unexpected exit) %s', (0, util_1.logDate)(), process.pid, this.disconnectCount, this.unexpectedCount, err.stack);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* reachReforkLimit default handler
|
|
147
|
+
*/
|
|
148
|
+
onReachReforkLimit() {
|
|
149
|
+
this.options.logger.error('[%s] [bootstrap:master:%s] worker died too fast (total %d disconnect, %d unexpected exit)', (0, util_1.logDate)(), process.pid, this.disconnectCount, this.unexpectedCount);
|
|
150
|
+
}
|
|
151
|
+
async killWorker(worker, timeout) {
|
|
152
|
+
// kill process, if SIGTERM not work, try SIGKILL
|
|
153
|
+
await this.closeWorker(worker);
|
|
154
|
+
await Promise.race([(0, events_1.once)(worker, 'exit'), (0, util_1.sleep)(timeout)]);
|
|
155
|
+
if (worker.killed)
|
|
156
|
+
return;
|
|
157
|
+
// SIGKILL: http://man7.org/linux/man-pages/man7/signal.7.html
|
|
158
|
+
// worker: https://github.com/nodejs/node/blob/master/lib/internal/cluster/worker.js#L22
|
|
159
|
+
// subProcess.kill is wrapped to subProcess.destroy, it will wait to disconnected.
|
|
160
|
+
(worker.process || worker).kill('SIGKILL');
|
|
161
|
+
}
|
|
162
|
+
async close(timeout = 2000) {
|
|
163
|
+
debug('run close');
|
|
164
|
+
this.isClosing = true;
|
|
165
|
+
await this.eventBus.stop();
|
|
166
|
+
for (const worker of this.workers.values()) {
|
|
167
|
+
worker['disableRefork'] = true;
|
|
168
|
+
await this.killWorker(worker, timeout);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
hasWorker(workerId) {
|
|
172
|
+
return this.workers.has(workerId);
|
|
173
|
+
}
|
|
174
|
+
getWorker(workerId) {
|
|
175
|
+
return this.workers.get(workerId);
|
|
176
|
+
}
|
|
177
|
+
getWorkerIds() {
|
|
178
|
+
return Array.from(this.workers.keys());
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
exports.AbstractForkManager = AbstractForkManager;
|
|
182
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Worker } from 'cluster';
|
|
3
|
+
import { ClusterOptions } from '../interface';
|
|
4
|
+
import { AbstractForkManager } from './base';
|
|
5
|
+
export declare class ClusterManager extends AbstractForkManager<Worker, ClusterOptions> {
|
|
6
|
+
readonly options: ClusterOptions;
|
|
7
|
+
constructor(options?: ClusterOptions);
|
|
8
|
+
createWorker(): any;
|
|
9
|
+
bindWorkerDisconnect(listener: (worker: Worker) => void): void;
|
|
10
|
+
bindWorkerExit(listener: (worker: Worker, code: any, signal: any) => void): void;
|
|
11
|
+
getWorkerId(worker: Worker): string;
|
|
12
|
+
isWorkerDead(worker: Worker): boolean;
|
|
13
|
+
closeWorker(worker: Worker): void;
|
|
14
|
+
createEventBus(options: any): any;
|
|
15
|
+
isPrimary(): boolean;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=cp.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClusterManager = void 0;
|
|
4
|
+
const event_bus_1 = require("@midwayjs/event-bus");
|
|
5
|
+
const base_1 = require("./base");
|
|
6
|
+
const cluster = require('cluster');
|
|
7
|
+
const util_1 = require("util");
|
|
8
|
+
const util_2 = require("../util");
|
|
9
|
+
const debug = (0, util_1.debuglog)('midway:bootstrap');
|
|
10
|
+
class ClusterManager extends base_1.AbstractForkManager {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
super(options);
|
|
13
|
+
this.options = options;
|
|
14
|
+
options.args = options.args || [];
|
|
15
|
+
options.execArgv = options.execArgv || [];
|
|
16
|
+
if ((0, util_2.isTypeScriptEnvironment)()) {
|
|
17
|
+
options.execArgv.push(...['--require', 'ts-node/register']);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
createWorker() {
|
|
21
|
+
if (cluster['setupPrimary']) {
|
|
22
|
+
cluster['setupPrimary'](this.options);
|
|
23
|
+
}
|
|
24
|
+
else if (cluster['setupMaster']) {
|
|
25
|
+
cluster['setupMaster'](this.options);
|
|
26
|
+
}
|
|
27
|
+
return cluster.fork({
|
|
28
|
+
MIDWAY_FORK_MODE: 'cluster',
|
|
29
|
+
MIDWAY_STICKY_MODE: this.options.sticky ? 'true' : 'false',
|
|
30
|
+
...this.options.env,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
bindWorkerDisconnect(listener) {
|
|
34
|
+
debug('Bind cluster.disconnect event');
|
|
35
|
+
cluster.on('disconnect', listener);
|
|
36
|
+
}
|
|
37
|
+
bindWorkerExit(listener) {
|
|
38
|
+
debug('Bind cluster.exit event');
|
|
39
|
+
cluster.on('exit', listener);
|
|
40
|
+
}
|
|
41
|
+
getWorkerId(worker) {
|
|
42
|
+
return String(worker.process.pid);
|
|
43
|
+
}
|
|
44
|
+
isWorkerDead(worker) {
|
|
45
|
+
return worker.isDead();
|
|
46
|
+
}
|
|
47
|
+
closeWorker(worker) {
|
|
48
|
+
worker.kill('SIGTERM');
|
|
49
|
+
}
|
|
50
|
+
createEventBus(options) {
|
|
51
|
+
return new event_bus_1.ChildProcessEventBus(options);
|
|
52
|
+
}
|
|
53
|
+
isPrimary() {
|
|
54
|
+
return !cluster.isWorker;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.ClusterManager = ClusterManager;
|
|
58
|
+
//# sourceMappingURL=cp.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { ThreadOptions } from '../interface';
|
|
3
|
+
import { AbstractForkManager } from './base';
|
|
4
|
+
import { Worker } from 'worker_threads';
|
|
5
|
+
export declare class ThreadManager extends AbstractForkManager<Worker, ThreadOptions> {
|
|
6
|
+
readonly options: ThreadOptions;
|
|
7
|
+
private exitListener;
|
|
8
|
+
constructor(options?: ThreadOptions);
|
|
9
|
+
createWorker(): Worker;
|
|
10
|
+
bindWorkerDisconnect(listener: (worker: Worker) => void): void;
|
|
11
|
+
bindWorkerExit(listener: (worker: Worker, code: any, signal: any) => void): void;
|
|
12
|
+
getWorkerId(worker: Worker): any;
|
|
13
|
+
isWorkerDead(worker: Worker): boolean;
|
|
14
|
+
closeWorker(worker: Worker): Promise<void>;
|
|
15
|
+
createEventBus(options: any): any;
|
|
16
|
+
isPrimary(): boolean;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=thread.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThreadManager = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const worker_threads_1 = require("worker_threads");
|
|
6
|
+
const event_bus_1 = require("@midwayjs/event-bus");
|
|
7
|
+
const util_1 = require("../util");
|
|
8
|
+
class ThreadManager extends base_1.AbstractForkManager {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.options = options;
|
|
12
|
+
options.argv = options.argv || [];
|
|
13
|
+
options.execArgv = options.execArgv || [];
|
|
14
|
+
process.env.MIDWAY_FORK_MODE = 'thread';
|
|
15
|
+
}
|
|
16
|
+
createWorker() {
|
|
17
|
+
let w;
|
|
18
|
+
let content = `
|
|
19
|
+
require(${JSON.stringify(this.options.exec)});
|
|
20
|
+
`;
|
|
21
|
+
// 当前是 ts 环境
|
|
22
|
+
if ((0, util_1.isTypeScriptEnvironment)()) {
|
|
23
|
+
content = `
|
|
24
|
+
require("ts-node/register/transpile-only");
|
|
25
|
+
${content}
|
|
26
|
+
`;
|
|
27
|
+
w = new worker_threads_1.Worker(content, { eval: true, env: worker_threads_1.SHARE_ENV });
|
|
28
|
+
w['_originThreadId'] = String(w.threadId);
|
|
29
|
+
this.options.logger.info('new worker thread with ts-node, threadId = %s.', this.getWorkerId(w));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
w = new worker_threads_1.Worker(content, { eval: true, env: worker_threads_1.SHARE_ENV });
|
|
33
|
+
this.options.logger.info('new worker thread, threadId = %s.', this.getWorkerId(w));
|
|
34
|
+
}
|
|
35
|
+
w.on('exit', code => {
|
|
36
|
+
this.exitListener(w, code);
|
|
37
|
+
});
|
|
38
|
+
return w;
|
|
39
|
+
}
|
|
40
|
+
bindWorkerDisconnect(listener) {
|
|
41
|
+
// this.disconnectListener = listener;
|
|
42
|
+
}
|
|
43
|
+
bindWorkerExit(listener) {
|
|
44
|
+
this.exitListener = listener;
|
|
45
|
+
}
|
|
46
|
+
getWorkerId(worker) {
|
|
47
|
+
return worker['_originThreadId'] || String(worker.threadId);
|
|
48
|
+
}
|
|
49
|
+
isWorkerDead(worker) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
async closeWorker(worker) {
|
|
53
|
+
await worker.terminate();
|
|
54
|
+
}
|
|
55
|
+
createEventBus(options) {
|
|
56
|
+
return new event_bus_1.ThreadEventBus(options);
|
|
57
|
+
}
|
|
58
|
+
isPrimary() {
|
|
59
|
+
return worker_threads_1.isMainThread;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.ThreadManager = ThreadManager;
|
|
63
|
+
//# sourceMappingURL=thread.js.map
|
package/dist/sticky.d.ts
ADDED
package/dist/sticky.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setupWorker = exports.setupStickyMaster = void 0;
|
|
4
|
+
const cluster = require('cluster');
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const randomId = () => (0, crypto_1.randomBytes)(8).toString('hex');
|
|
7
|
+
function setupStickyMaster(httpServer, opts = {}) {
|
|
8
|
+
const options = {
|
|
9
|
+
loadBalancingMethod: 'least-connection',
|
|
10
|
+
...opts,
|
|
11
|
+
};
|
|
12
|
+
const sessionIdToWorker = new Map();
|
|
13
|
+
const sidRegex = /sid=([\w-]{20})/;
|
|
14
|
+
let currentIndex = 0; // for round-robin load balancing
|
|
15
|
+
const computeWorkerId = data => {
|
|
16
|
+
const match = sidRegex.exec(data);
|
|
17
|
+
if (match) {
|
|
18
|
+
const sid = match[1];
|
|
19
|
+
const workerId = sessionIdToWorker.get(sid);
|
|
20
|
+
if (workerId && cluster.workers[workerId]) {
|
|
21
|
+
return workerId;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
switch (options.loadBalancingMethod) {
|
|
25
|
+
case 'random': {
|
|
26
|
+
const workerIds = Object.keys(cluster.workers);
|
|
27
|
+
return workerIds[Math.floor(Math.random() * workerIds.length)];
|
|
28
|
+
}
|
|
29
|
+
case 'round-robin': {
|
|
30
|
+
const workerIds = Object.keys(cluster.workers);
|
|
31
|
+
currentIndex++;
|
|
32
|
+
if (currentIndex >= workerIds.length) {
|
|
33
|
+
currentIndex = 0;
|
|
34
|
+
}
|
|
35
|
+
return workerIds[currentIndex];
|
|
36
|
+
}
|
|
37
|
+
case 'least-connection':
|
|
38
|
+
// eslint-disable-next-line no-case-declarations
|
|
39
|
+
let leastActiveWorker;
|
|
40
|
+
for (const id in cluster.workers) {
|
|
41
|
+
const worker = cluster.workers[id];
|
|
42
|
+
if (leastActiveWorker === undefined) {
|
|
43
|
+
leastActiveWorker = worker;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const c1 = worker['clientsCount'] || 0;
|
|
47
|
+
const c2 = leastActiveWorker['clientsCount'] || 0;
|
|
48
|
+
if (c1 < c2) {
|
|
49
|
+
leastActiveWorker = worker;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return leastActiveWorker.id;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
httpServer.on('connection', socket => {
|
|
57
|
+
let workerId, connectionId;
|
|
58
|
+
const sendCallback = err => {
|
|
59
|
+
if (err) {
|
|
60
|
+
socket.destroy();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
socket.on('data', buffer => {
|
|
64
|
+
const data = buffer.toString();
|
|
65
|
+
if (workerId && connectionId) {
|
|
66
|
+
cluster.workers[workerId].send({ type: 'sticky:http-chunk', data, connectionId }, sendCallback);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
workerId = computeWorkerId(data);
|
|
70
|
+
const mayHaveMultipleChunks = !(data.startsWith('GET') ||
|
|
71
|
+
data
|
|
72
|
+
.substring(0, data.indexOf('\r\n\r\n'))
|
|
73
|
+
.includes('pgrade: websocket'));
|
|
74
|
+
socket.pause();
|
|
75
|
+
if (mayHaveMultipleChunks) {
|
|
76
|
+
connectionId = randomId();
|
|
77
|
+
}
|
|
78
|
+
cluster.workers[workerId].send({ type: 'sticky:connection', data, connectionId }, socket, {
|
|
79
|
+
keepOpen: mayHaveMultipleChunks,
|
|
80
|
+
}, sendCallback);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
// this is needed to properly detect the end of the HTTP request body
|
|
84
|
+
httpServer.on('request', req => {
|
|
85
|
+
req.on('data', () => { });
|
|
86
|
+
});
|
|
87
|
+
cluster.on('message', (worker, { type, data }) => {
|
|
88
|
+
switch (type) {
|
|
89
|
+
case 'sticky:connection':
|
|
90
|
+
sessionIdToWorker.set(data, worker.id);
|
|
91
|
+
if (options.loadBalancingMethod === 'least-connection') {
|
|
92
|
+
worker['clientsCount'] = (worker['clientsCount'] || 0) + 1;
|
|
93
|
+
}
|
|
94
|
+
break;
|
|
95
|
+
case 'sticky:disconnection':
|
|
96
|
+
sessionIdToWorker.delete(data);
|
|
97
|
+
if (options.loadBalancingMethod === 'least-connection') {
|
|
98
|
+
worker['clientsCount']--;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
exports.setupStickyMaster = setupStickyMaster;
|
|
105
|
+
function setupWorker(io) {
|
|
106
|
+
// store connections that may receive multiple chunks
|
|
107
|
+
const sockets = new Map();
|
|
108
|
+
process.on('message', ({ type, data, connectionId }, socket) => {
|
|
109
|
+
switch (type) {
|
|
110
|
+
case 'sticky:connection':
|
|
111
|
+
if (!socket) {
|
|
112
|
+
// might happen if the socket is closed during the transfer to the worker
|
|
113
|
+
// see https://nodejs.org/api/child_process.html#child_process_example_sending_a_socket_object
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
io.httpServer.emit('connection', socket); // inject connection
|
|
117
|
+
socket.emit('data', Buffer.from(data)); // republish first chunk
|
|
118
|
+
socket.resume();
|
|
119
|
+
if (connectionId) {
|
|
120
|
+
sockets.set(connectionId, socket);
|
|
121
|
+
socket.on('close', () => {
|
|
122
|
+
sockets.delete(connectionId);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
break;
|
|
126
|
+
case 'sticky:http-chunk': {
|
|
127
|
+
const socket = sockets.get(connectionId);
|
|
128
|
+
if (socket) {
|
|
129
|
+
socket.emit('data', Buffer.from(data));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
const ignoreError = () => { }; // the next request will fail anyway
|
|
135
|
+
io.engine.on('connection', socket => {
|
|
136
|
+
process.send({ type: 'sticky:connection', data: socket.id }, ignoreError);
|
|
137
|
+
socket.once('close', () => {
|
|
138
|
+
process.send({ type: 'sticky:disconnection', data: socket.id }, ignoreError);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
exports.setupWorker = setupWorker;
|
|
143
|
+
//# sourceMappingURL=sticky.js.map
|
package/dist/util.d.ts
ADDED
package/dist/util.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTypeScriptEnvironment = exports.sleep = exports.logDate = void 0;
|
|
4
|
+
function logDate() {
|
|
5
|
+
const d = new Date();
|
|
6
|
+
let date = d.getDate();
|
|
7
|
+
if (date < 10) {
|
|
8
|
+
date = '0' + date;
|
|
9
|
+
}
|
|
10
|
+
let month = d.getMonth() + 1;
|
|
11
|
+
if (month < 10) {
|
|
12
|
+
month = '0' + month;
|
|
13
|
+
}
|
|
14
|
+
let hours = d.getHours();
|
|
15
|
+
if (hours < 10) {
|
|
16
|
+
hours = '0' + hours;
|
|
17
|
+
}
|
|
18
|
+
let mintues = d.getMinutes();
|
|
19
|
+
if (mintues < 10) {
|
|
20
|
+
mintues = '0' + mintues;
|
|
21
|
+
}
|
|
22
|
+
let seconds = d.getSeconds();
|
|
23
|
+
if (seconds < 10) {
|
|
24
|
+
seconds = '0' + seconds;
|
|
25
|
+
}
|
|
26
|
+
let milliseconds = d.getMilliseconds();
|
|
27
|
+
if (milliseconds < 10) {
|
|
28
|
+
milliseconds = '00' + milliseconds;
|
|
29
|
+
}
|
|
30
|
+
else if (milliseconds < 100) {
|
|
31
|
+
milliseconds = '0' + milliseconds;
|
|
32
|
+
}
|
|
33
|
+
return (d.getFullYear() +
|
|
34
|
+
'-' +
|
|
35
|
+
month +
|
|
36
|
+
'-' +
|
|
37
|
+
date +
|
|
38
|
+
' ' +
|
|
39
|
+
hours +
|
|
40
|
+
':' +
|
|
41
|
+
mintues +
|
|
42
|
+
':' +
|
|
43
|
+
seconds +
|
|
44
|
+
'.' +
|
|
45
|
+
milliseconds);
|
|
46
|
+
}
|
|
47
|
+
exports.logDate = logDate;
|
|
48
|
+
async function sleep(timeout) {
|
|
49
|
+
return new Promise(resolve => {
|
|
50
|
+
setTimeout(resolve, timeout);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.sleep = sleep;
|
|
54
|
+
function isTypeScriptEnvironment() {
|
|
55
|
+
const TS_MODE_PROCESS_FLAG = process.env.MIDWAY_TS_MODE;
|
|
56
|
+
if ('false' === TS_MODE_PROCESS_FLAG) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// eslint-disable-next-line node/no-deprecated-api
|
|
60
|
+
return TS_MODE_PROCESS_FLAG === 'true' || !!require.extensions['.ts'];
|
|
61
|
+
}
|
|
62
|
+
exports.isTypeScriptEnvironment = isTypeScriptEnvironment;
|
|
63
|
+
//# sourceMappingURL=util.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@midwayjs/bootstrap",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "midwayjs bootstrap",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -21,13 +21,12 @@
|
|
|
21
21
|
],
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@midwayjs/async-hooks-context-manager": "^3.
|
|
24
|
+
"@midwayjs/async-hooks-context-manager": "^3.9.0",
|
|
25
|
+
"@midwayjs/event-bus": "^1.0.1"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"@midwayjs/core": "^3.
|
|
28
|
+
"@midwayjs/core": "^3.9.0",
|
|
28
29
|
"@midwayjs/logger": "^2.15.0",
|
|
29
|
-
"@midwayjs/socketio": "^3.8.0",
|
|
30
|
-
"@midwayjs/web": "^3.8.0",
|
|
31
30
|
"request": "2.88.2",
|
|
32
31
|
"socket.io-client": "4.5.3"
|
|
33
32
|
},
|
|
@@ -37,7 +36,7 @@
|
|
|
37
36
|
"url": "https://github.com/midwayjs/midway.git"
|
|
38
37
|
},
|
|
39
38
|
"engines": {
|
|
40
|
-
"node": ">=12"
|
|
39
|
+
"node": ">=12.11.0"
|
|
41
40
|
},
|
|
42
|
-
"gitHead": "
|
|
41
|
+
"gitHead": "5f6603d2c9606fc6fc7ece71f956e89e394efeee"
|
|
43
42
|
}
|