@midwayjs/bootstrap 3.7.3 → 3.8.1-beta.1
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 → bootstrap/bootstrap.d.ts} +5 -4
- package/dist/{bootstrap.js → bootstrap/bootstrap.js} +0 -0
- package/dist/bootstrap/cluster.d.ts +18 -0
- package/dist/bootstrap/cluster.js +43 -0
- package/dist/fork/base.d.ts +42 -0
- package/dist/fork/base.js +169 -0
- package/dist/fork/cp.d.ts +16 -0
- package/dist/fork/cp.js +53 -0
- package/dist/fork/thread.d.ts +17 -0
- package/dist/fork/thread.js +71 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +20 -2
- package/dist/interface.d.ts +28 -0
- package/dist/interface.js +3 -0
- package/dist/util.d.ts +3 -0
- package/dist/util.js +43 -0
- package/package.json +8 -7
- package/LICENSE +0 -21
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IMidwayBootstrapOptions, IMidwayContainer } from '@midwayjs/core';
|
|
2
|
+
import { IMidwayLogger } from '@midwayjs/logger';
|
|
2
3
|
export declare function isTypeScriptEnvironment(): boolean;
|
|
3
4
|
export declare class BootstrapStarter {
|
|
4
5
|
protected appDir: string;
|
|
@@ -14,15 +15,15 @@ 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 getStarter(): BootstrapStarter;
|
|
26
27
|
static run(): Promise<void>;
|
|
27
28
|
static stop(): Promise<void>;
|
|
28
29
|
static reset(): void;
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Bootstrap, BootstrapStarter } from './bootstrap';
|
|
2
|
+
import { ClusterBootstrapOptions } from '../interface';
|
|
3
|
+
export declare class ClusterBootstrapStarter extends BootstrapStarter {
|
|
4
|
+
protected globalOptions: ClusterBootstrapOptions;
|
|
5
|
+
private clusterManager;
|
|
6
|
+
init(): Promise<any>;
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
stop(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare class ClusterBootstrap extends Bootstrap {
|
|
11
|
+
/**
|
|
12
|
+
* set global configuration for midway
|
|
13
|
+
* @param configuration
|
|
14
|
+
*/
|
|
15
|
+
static configure(configuration?: ClusterBootstrapOptions): typeof Bootstrap;
|
|
16
|
+
static getStarter(): BootstrapStarter;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=cluster.d.ts.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClusterBootstrap = exports.ClusterBootstrapStarter = void 0;
|
|
4
|
+
const bootstrap_1 = require("./bootstrap");
|
|
5
|
+
const cp_1 = require("../fork/cp");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
class ClusterBootstrapStarter extends bootstrap_1.BootstrapStarter {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.globalOptions = {};
|
|
11
|
+
}
|
|
12
|
+
async init() {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
async run() {
|
|
16
|
+
this.clusterManager = new cp_1.ClusterManager({
|
|
17
|
+
exec: (0, path_1.join)(__dirname, 'bootstrap'),
|
|
18
|
+
...this.globalOptions,
|
|
19
|
+
});
|
|
20
|
+
await this.clusterManager.start();
|
|
21
|
+
}
|
|
22
|
+
async stop() {
|
|
23
|
+
await this.clusterManager.close();
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.ClusterBootstrapStarter = ClusterBootstrapStarter;
|
|
27
|
+
class ClusterBootstrap extends bootstrap_1.Bootstrap {
|
|
28
|
+
/**
|
|
29
|
+
* set global configuration for midway
|
|
30
|
+
* @param configuration
|
|
31
|
+
*/
|
|
32
|
+
static configure(configuration = {}) {
|
|
33
|
+
return super.configure(configuration);
|
|
34
|
+
}
|
|
35
|
+
static getStarter() {
|
|
36
|
+
if (!this.starter) {
|
|
37
|
+
this.starter = new ClusterBootstrapStarter();
|
|
38
|
+
}
|
|
39
|
+
return this.starter;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.ClusterBootstrap = ClusterBootstrap;
|
|
43
|
+
//# sourceMappingURL=cluster.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ForkOptions } from '../interface';
|
|
2
|
+
import type { IEventBus } 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: Set<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
|
+
abstract createWorker(oldWorker?: T): T;
|
|
35
|
+
abstract bindWorkerDisconnect(listener: (worker: T) => void): void;
|
|
36
|
+
abstract bindWorkerExit(listener: (worker: T, code: any, signal: any) => void): void;
|
|
37
|
+
abstract getWorkerId(worker: T): string;
|
|
38
|
+
abstract isWorkerDead(worker: T): boolean;
|
|
39
|
+
abstract closeWorker(worker: T): any;
|
|
40
|
+
abstract createEventBus(): IEventBus<T>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1,169 @@
|
|
|
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 Set();
|
|
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
|
+
this.eventBus = this.createEventBus();
|
|
26
|
+
}
|
|
27
|
+
async start() {
|
|
28
|
+
this.bindWorkerDisconnect(worker => {
|
|
29
|
+
debug(' - worker(%s): trigger event = disconnect', this.getWorkerId(worker));
|
|
30
|
+
const log = this.options.logger[worker['disableRefork'] ? 'info' : 'error'];
|
|
31
|
+
this.disconnectCount++;
|
|
32
|
+
const isDead = this.isWorkerDead(worker);
|
|
33
|
+
if (isDead) {
|
|
34
|
+
debug(' - worker(%s): worker is dead', this.getWorkerId(worker));
|
|
35
|
+
// worker has terminated before disconnect
|
|
36
|
+
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));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (worker['disableRefork']) {
|
|
40
|
+
debug(' - worker(%s): worker is disableRefork(maybe terminated by master)', this.getWorkerId(worker));
|
|
41
|
+
// worker has terminated by master
|
|
42
|
+
log("[%s] [bootstrap:master:%s] don't fork, because worker:%s will be kill soon", (0, util_1.logDate)(), process.pid, this.getWorkerId(worker));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.disconnects[this.getWorkerId(worker)] = (0, util_1.logDate)();
|
|
46
|
+
this.tryToRefork(worker);
|
|
47
|
+
});
|
|
48
|
+
this.bindWorkerExit((worker, code, signal) => {
|
|
49
|
+
debug(' - worker(%s): trigger event = exit', this.getWorkerId(worker));
|
|
50
|
+
// remove worker
|
|
51
|
+
// this.workers.delete(worker);
|
|
52
|
+
if (worker['disableRefork']) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const isExpected = !!this.disconnects[this.getWorkerId(worker)];
|
|
56
|
+
debug(' - worker(%s): isExpected=%s', this.getWorkerId(worker), isExpected);
|
|
57
|
+
if (isExpected) {
|
|
58
|
+
delete this.disconnects[this.getWorkerId(worker)];
|
|
59
|
+
// worker disconnect first, exit expected
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
debug(' - worker(%s): isWorkerDead=%s', this.getWorkerId(worker), this.isWorkerDead(worker));
|
|
63
|
+
if (this.isWorkerDead(worker)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
debug(' - worker(%s): unexpectedCount will add');
|
|
67
|
+
this.unexpectedCount++;
|
|
68
|
+
this.tryToRefork(worker);
|
|
69
|
+
this.onUnexpected(worker, code, signal);
|
|
70
|
+
});
|
|
71
|
+
this.hub.on('reachReforkLimit', this.onReachReforkLimit.bind(this));
|
|
72
|
+
// defer to set the listeners
|
|
73
|
+
// so you can listen this by your own
|
|
74
|
+
setImmediate(() => {
|
|
75
|
+
if (process.listeners('uncaughtException').length === 0) {
|
|
76
|
+
process.on('uncaughtException', this.onerror.bind(this));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
for (let i = 0; i < this.options.count; i++) {
|
|
80
|
+
const w = this.createWorker();
|
|
81
|
+
debug(' - worker(%s) created', this.getWorkerId(w));
|
|
82
|
+
this.workers.add(w);
|
|
83
|
+
}
|
|
84
|
+
await this.eventBus.start();
|
|
85
|
+
}
|
|
86
|
+
tryToRefork(oldWorker) {
|
|
87
|
+
if (this.allowRefork()) {
|
|
88
|
+
debug(' - worker(%s): allow refork and will fork new', this.getWorkerId(oldWorker));
|
|
89
|
+
const newWorker = this.createWorker(oldWorker);
|
|
90
|
+
this.workers.add(newWorker);
|
|
91
|
+
debug('----after create', newWorker.process.pid);
|
|
92
|
+
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']);
|
|
93
|
+
this.eventBus.addWorker(newWorker);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
debug(' - worker(%s): forbidden refork and will stop', this.getWorkerId(oldWorker));
|
|
97
|
+
this.options.logger.info("[%s] [bootstrap:master:%s] don't fork new work (refork: %s)", (0, util_1.logDate)(), process.pid, this.options.refork);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* allow refork
|
|
102
|
+
*/
|
|
103
|
+
allowRefork() {
|
|
104
|
+
if (!this.options.refork || this.isClosing) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const times = this.reforks.push(Date.now());
|
|
108
|
+
if (times > this.options.limit) {
|
|
109
|
+
this.reforks.shift();
|
|
110
|
+
}
|
|
111
|
+
const span = this.reforks[this.reforks.length - 1] - this.reforks[0];
|
|
112
|
+
const canFork = this.reforks.length < this.options.limit || span > this.options.duration;
|
|
113
|
+
if (!canFork) {
|
|
114
|
+
this.hub.emit('reachReforkLimit');
|
|
115
|
+
}
|
|
116
|
+
return canFork;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* uncaughtException default handler
|
|
120
|
+
*/
|
|
121
|
+
onerror(err) {
|
|
122
|
+
if (!err) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.options.logger.error('[%s] [bootstrap:master:%s] master uncaughtException: %s', (0, util_1.logDate)(), process.pid, err.stack);
|
|
126
|
+
this.options.logger.error(err);
|
|
127
|
+
this.options.logger.error('(total %d disconnect, %d unexpected exit)', this.disconnectCount, this.unexpectedCount);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* unexpectedExit default handler
|
|
131
|
+
*/
|
|
132
|
+
onUnexpected(worker, code, signal) {
|
|
133
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
134
|
+
const propertyName = worker.hasOwnProperty('exitedAfterDisconnect')
|
|
135
|
+
? 'exitedAfterDisconnect'
|
|
136
|
+
: 'suicide';
|
|
137
|
+
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']));
|
|
138
|
+
err.name = 'WorkerDiedUnexpectedError';
|
|
139
|
+
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);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* reachReforkLimit default handler
|
|
143
|
+
*/
|
|
144
|
+
onReachReforkLimit() {
|
|
145
|
+
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);
|
|
146
|
+
}
|
|
147
|
+
async killWorker(worker, timeout) {
|
|
148
|
+
// kill process, if SIGTERM not work, try SIGKILL
|
|
149
|
+
await this.closeWorker(worker);
|
|
150
|
+
await Promise.race([(0, events_1.once)(worker, 'exit'), (0, util_1.sleep)(timeout)]);
|
|
151
|
+
if (worker.killed)
|
|
152
|
+
return;
|
|
153
|
+
// SIGKILL: http://man7.org/linux/man-pages/man7/signal.7.html
|
|
154
|
+
// worker: https://github.com/nodejs/node/blob/master/lib/internal/cluster/worker.js#L22
|
|
155
|
+
// subProcess.kill is wrapped to subProcess.destroy, it will wait to disconnected.
|
|
156
|
+
(worker.process || worker).kill('SIGKILL');
|
|
157
|
+
}
|
|
158
|
+
async close(timeout = 2000) {
|
|
159
|
+
debug('run close');
|
|
160
|
+
this.isClosing = true;
|
|
161
|
+
await this.eventBus.stop();
|
|
162
|
+
for (const worker of this.workers) {
|
|
163
|
+
worker['disableRefork'] = true;
|
|
164
|
+
await this.killWorker(worker, timeout);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
exports.AbstractForkManager = AbstractForkManager;
|
|
169
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
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(): any;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=cp.d.ts.map
|
package/dist/fork/cp.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClusterManager = void 0;
|
|
4
|
+
const cp_1 = require("@midwayjs/event-bus/dist/cp");
|
|
5
|
+
const base_1 = require("./base");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const cluster = require('cluster');
|
|
8
|
+
const util_1 = 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, path_1.extname)(this.options.exec) === '.ts') {
|
|
17
|
+
options.execArgv.push(...['--require', 'ts-node/register']);
|
|
18
|
+
}
|
|
19
|
+
debug('Init cluster manager with options: %j', options);
|
|
20
|
+
}
|
|
21
|
+
createWorker() {
|
|
22
|
+
if (cluster['setupPrimary']) {
|
|
23
|
+
cluster['setupPrimary'](this.options);
|
|
24
|
+
}
|
|
25
|
+
else if (cluster['setupMaster']) {
|
|
26
|
+
cluster['setupMaster'](this.options);
|
|
27
|
+
}
|
|
28
|
+
console.log('----cluster=', process.pid);
|
|
29
|
+
return cluster.fork();
|
|
30
|
+
}
|
|
31
|
+
bindWorkerDisconnect(listener) {
|
|
32
|
+
debug('Bind cluster.disconnect event');
|
|
33
|
+
cluster.on('disconnect', listener);
|
|
34
|
+
}
|
|
35
|
+
bindWorkerExit(listener) {
|
|
36
|
+
debug('Bind cluster.exit event');
|
|
37
|
+
cluster.on('exit', listener);
|
|
38
|
+
}
|
|
39
|
+
getWorkerId(worker) {
|
|
40
|
+
return String(worker.process.pid);
|
|
41
|
+
}
|
|
42
|
+
isWorkerDead(worker) {
|
|
43
|
+
return worker.isDead();
|
|
44
|
+
}
|
|
45
|
+
closeWorker(worker) {
|
|
46
|
+
worker.kill('SIGTERM');
|
|
47
|
+
}
|
|
48
|
+
createEventBus() {
|
|
49
|
+
return new cp_1.ChildProcessEventBus();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.ClusterManager = ClusterManager;
|
|
53
|
+
//# sourceMappingURL=cp.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { ThreadOptions } from '../interface';
|
|
3
|
+
import { AbstractForkManager } from './base';
|
|
4
|
+
import type { Worker as ThreadWorker } from 'worker_threads';
|
|
5
|
+
export declare class ThreadManager extends AbstractForkManager<ThreadWorker, ThreadOptions> {
|
|
6
|
+
readonly options: ThreadOptions;
|
|
7
|
+
private exitListener;
|
|
8
|
+
constructor(options?: ThreadOptions);
|
|
9
|
+
createWorker(): ThreadWorker;
|
|
10
|
+
bindWorkerDisconnect(listener: (worker: ThreadWorker) => void): void;
|
|
11
|
+
bindWorkerExit(listener: (worker: ThreadWorker, code: any, signal: any) => void): void;
|
|
12
|
+
getWorkerId(worker: ThreadWorker): any;
|
|
13
|
+
isWorkerDead(worker: ThreadWorker): boolean;
|
|
14
|
+
closeWorker(worker: ThreadWorker): Promise<void>;
|
|
15
|
+
createEventBus(): any;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=thread.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThreadManager = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const base_1 = require("./base");
|
|
6
|
+
let threads = null;
|
|
7
|
+
let shareEnv = null;
|
|
8
|
+
let Worker = null;
|
|
9
|
+
let ThreadEventBus = null;
|
|
10
|
+
try {
|
|
11
|
+
// eslint-disable-next-line node/no-unsupported-features/node-builtins
|
|
12
|
+
threads = require('worker_threads');
|
|
13
|
+
shareEnv = threads.SHARE_ENV;
|
|
14
|
+
Worker = threads.Worker;
|
|
15
|
+
ThreadEventBus = require('@midwayjs/event-bus').ThreadEventBus;
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
// ignore not support worker_threads
|
|
19
|
+
}
|
|
20
|
+
class ThreadManager extends base_1.AbstractForkManager {
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
super(options);
|
|
23
|
+
this.options = options;
|
|
24
|
+
options.argv = options.argv || [];
|
|
25
|
+
options.execArgv = options.execArgv || [];
|
|
26
|
+
}
|
|
27
|
+
createWorker() {
|
|
28
|
+
let w;
|
|
29
|
+
let content = `
|
|
30
|
+
require(${JSON.stringify(this.options.exec)});
|
|
31
|
+
`;
|
|
32
|
+
// 当前是 ts 环境
|
|
33
|
+
if ((0, path_1.extname)(this.options.exec) === '.ts') {
|
|
34
|
+
content = `
|
|
35
|
+
require("ts-node/register/transpile-only");
|
|
36
|
+
${content}
|
|
37
|
+
`;
|
|
38
|
+
w = new Worker(content, { eval: true, env: shareEnv });
|
|
39
|
+
w['_originThreadId'] = String(w.threadId);
|
|
40
|
+
this.options.logger.info('new worker thread with ts-node, threadId = %s.', this.getWorkerId(w));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
w = new Worker(content, { eval: true, env: shareEnv });
|
|
44
|
+
this.options.logger.info('new worker thread, threadId = %s.', this.getWorkerId(w));
|
|
45
|
+
}
|
|
46
|
+
w.on('exit', code => {
|
|
47
|
+
this.exitListener(w, code);
|
|
48
|
+
});
|
|
49
|
+
return w;
|
|
50
|
+
}
|
|
51
|
+
bindWorkerDisconnect(listener) {
|
|
52
|
+
// this.disconnectListener = listener;
|
|
53
|
+
}
|
|
54
|
+
bindWorkerExit(listener) {
|
|
55
|
+
this.exitListener = listener;
|
|
56
|
+
}
|
|
57
|
+
getWorkerId(worker) {
|
|
58
|
+
return worker['_originThreadId'] || String(worker.threadId);
|
|
59
|
+
}
|
|
60
|
+
isWorkerDead(worker) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
async closeWorker(worker) {
|
|
64
|
+
await worker.terminate();
|
|
65
|
+
}
|
|
66
|
+
createEventBus() {
|
|
67
|
+
return new ThreadEventBus();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.ThreadManager = ThreadManager;
|
|
71
|
+
//# sourceMappingURL=thread.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './interface';
|
|
2
|
+
export { isTypeScriptEnvironment, Bootstrap, BootstrapStarter, } from './bootstrap/bootstrap';
|
|
3
|
+
export { ClusterBootstrap, ClusterBootstrapStarter } from './bootstrap/cluster';
|
|
2
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
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;
|
|
4
|
-
|
|
17
|
+
exports.ClusterBootstrapStarter = exports.ClusterBootstrap = exports.BootstrapStarter = exports.Bootstrap = exports.isTypeScriptEnvironment = void 0;
|
|
18
|
+
__exportStar(require("./interface"), exports);
|
|
19
|
+
var bootstrap_1 = require("./bootstrap/bootstrap");
|
|
5
20
|
Object.defineProperty(exports, "isTypeScriptEnvironment", { enumerable: true, get: function () { return bootstrap_1.isTypeScriptEnvironment; } });
|
|
6
21
|
Object.defineProperty(exports, "Bootstrap", { enumerable: true, get: function () { return bootstrap_1.Bootstrap; } });
|
|
7
22
|
Object.defineProperty(exports, "BootstrapStarter", { enumerable: true, get: function () { return bootstrap_1.BootstrapStarter; } });
|
|
23
|
+
var cluster_1 = require("./bootstrap/cluster");
|
|
24
|
+
Object.defineProperty(exports, "ClusterBootstrap", { enumerable: true, get: function () { return cluster_1.ClusterBootstrap; } });
|
|
25
|
+
Object.defineProperty(exports, "ClusterBootstrapStarter", { enumerable: true, get: function () { return cluster_1.ClusterBootstrapStarter; } });
|
|
8
26
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/// <reference types="node" />
|
|
4
|
+
import type { IMidwayBootstrapOptions } from '@midwayjs/core';
|
|
5
|
+
import type { IMidwayLogger } from '@midwayjs/logger';
|
|
6
|
+
import { ClusterSettings } from 'cluster';
|
|
7
|
+
import { WorkerOptions } from 'worker_threads';
|
|
8
|
+
export interface ForkOptions {
|
|
9
|
+
exec?: string;
|
|
10
|
+
/**
|
|
11
|
+
* worker num, default is `os.cpus().length`
|
|
12
|
+
*/
|
|
13
|
+
count?: number;
|
|
14
|
+
/**
|
|
15
|
+
* refork when disconect and unexpected exit, default is `true`
|
|
16
|
+
*/
|
|
17
|
+
refork?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* restart limit, default is `60`
|
|
20
|
+
*/
|
|
21
|
+
limit?: number;
|
|
22
|
+
duration?: number;
|
|
23
|
+
logger?: IMidwayLogger | Console;
|
|
24
|
+
}
|
|
25
|
+
export declare type ClusterOptions = ForkOptions & ClusterSettings;
|
|
26
|
+
export declare type ThreadOptions = ForkOptions & WorkerOptions;
|
|
27
|
+
export declare type ClusterBootstrapOptions = IMidwayBootstrapOptions & ClusterOptions;
|
|
28
|
+
//# sourceMappingURL=interface.d.ts.map
|
package/dist/util.d.ts
ADDED
package/dist/util.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
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() + '-' + month + '-' + date + ' ' +
|
|
34
|
+
hours + ':' + mintues + ':' + seconds + ('.') + milliseconds;
|
|
35
|
+
}
|
|
36
|
+
exports.logDate = logDate;
|
|
37
|
+
async function sleep(timeout) {
|
|
38
|
+
return new Promise(resolve => {
|
|
39
|
+
setTimeout(resolve, timeout);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.sleep = sleep;
|
|
43
|
+
//# 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.8.1-beta.1",
|
|
4
4
|
"description": "midwayjs bootstrap",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -21,23 +21,24 @@
|
|
|
21
21
|
],
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@midwayjs/async-hooks-context-manager": "^3.
|
|
24
|
+
"@midwayjs/async-hooks-context-manager": "^3.8.0",
|
|
25
|
+
"@midwayjs/event-bus": "0.0.1"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"@midwayjs/core": "^3.
|
|
28
|
+
"@midwayjs/core": "^3.8.0",
|
|
28
29
|
"@midwayjs/logger": "^2.15.0",
|
|
29
|
-
"@midwayjs/socketio": "^3.
|
|
30
|
-
"@midwayjs/web": "^3.
|
|
30
|
+
"@midwayjs/socketio": "^3.8.0",
|
|
31
|
+
"@midwayjs/web": "^3.8.0",
|
|
31
32
|
"request": "2.88.2",
|
|
32
33
|
"socket.io-client": "4.5.3"
|
|
33
34
|
},
|
|
34
35
|
"author": "Harry Chen <czy88840616@gmail.com>",
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|
|
37
|
-
"url": "
|
|
38
|
+
"url": "https://github.com/midwayjs/midway.git"
|
|
38
39
|
},
|
|
39
40
|
"engines": {
|
|
40
41
|
"node": ">=12"
|
|
41
42
|
},
|
|
42
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "a603d2348d6141f8f723901498f03a162a037708"
|
|
43
44
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2013 - Now midwayjs
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|