@midwayjs/bootstrap 3.9.0 → 3.10.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.
@@ -38,9 +38,9 @@ export interface IForkManager<T> {
38
38
  isWorkerDead(worker: T): boolean;
39
39
  isPrimary(): boolean;
40
40
  }
41
- export declare type ClusterOptions = ForkOptions & ClusterSettings & {
41
+ export type ClusterOptions = ForkOptions & ClusterSettings & {
42
42
  sticky?: boolean;
43
43
  stickyLoadBalancingMethod?: 'random' | 'round-robin' | 'least-connection';
44
44
  };
45
- export declare type ThreadOptions = ForkOptions & WorkerOptions;
45
+ export type ThreadOptions = ForkOptions & WorkerOptions;
46
46
  //# sourceMappingURL=interface.d.ts.map
@@ -10,6 +10,7 @@ export declare abstract class AbstractForkManager<T, ClusterOptions extends Fork
10
10
  protected workers: Map<string, T>;
11
11
  protected eventBus: IEventBus<T>;
12
12
  private isClosing;
13
+ private exitListener;
13
14
  protected constructor(options: ClusterOptions);
14
15
  start(): Promise<void>;
15
16
  protected tryToRefork(oldWorker: T): void;
@@ -30,10 +31,22 @@ export declare abstract class AbstractForkManager<T, ClusterOptions extends Fork
30
31
  */
31
32
  protected onReachReforkLimit(): void;
32
33
  protected killWorker(worker: any, timeout: any): Promise<void>;
33
- close(timeout?: number): Promise<void>;
34
+ stop(timeout?: number): Promise<void>;
34
35
  hasWorker(workerId: string): boolean;
35
36
  getWorker(workerId: string): T;
36
37
  getWorkerIds(): string[];
38
+ onStop(exitListener: any): void;
39
+ protected bindClose(): void;
40
+ /**
41
+ * on bootstrap receive a exit signal
42
+ * @param signal
43
+ */
44
+ private onSignal;
45
+ /**
46
+ * on bootstrap process exit
47
+ * @param code
48
+ */
49
+ private onMasterExit;
37
50
  abstract createWorker(oldWorker?: T): T;
38
51
  abstract bindWorkerDisconnect(listener: (worker: T) => void): void;
39
52
  abstract bindWorkerExit(listener: (worker: T, code: any, signal: any) => void): void;
@@ -72,6 +72,7 @@ class AbstractForkManager {
72
72
  this.tryToRefork(worker);
73
73
  this.onUnexpected(worker, code, signal);
74
74
  });
75
+ this.bindClose();
75
76
  this.hub.on('reachReforkLimit', this.onReachReforkLimit.bind(this));
76
77
  // defer to set the listeners
77
78
  // so you can listen this by your own
@@ -159,7 +160,7 @@ class AbstractForkManager {
159
160
  // subProcess.kill is wrapped to subProcess.destroy, it will wait to disconnected.
160
161
  (worker.process || worker).kill('SIGKILL');
161
162
  }
162
- async close(timeout = 2000) {
163
+ async stop(timeout = 2000) {
163
164
  debug('run close');
164
165
  this.isClosing = true;
165
166
  await this.eventBus.stop();
@@ -167,6 +168,9 @@ class AbstractForkManager {
167
168
  worker['disableRefork'] = true;
168
169
  await this.killWorker(worker, timeout);
169
170
  }
171
+ if (this.exitListener) {
172
+ await this.exitListener();
173
+ }
170
174
  }
171
175
  hasWorker(workerId) {
172
176
  return this.workers.has(workerId);
@@ -177,6 +181,43 @@ class AbstractForkManager {
177
181
  getWorkerIds() {
178
182
  return Array.from(this.workers.keys());
179
183
  }
184
+ onStop(exitListener) {
185
+ this.exitListener = exitListener;
186
+ }
187
+ bindClose() {
188
+ // kill(2) Ctrl-C
189
+ process.once('SIGINT', this.onSignal.bind(this, 'SIGINT'));
190
+ // kill(3) Ctrl-\
191
+ process.once('SIGQUIT', this.onSignal.bind(this, 'SIGQUIT'));
192
+ // kill(15) default
193
+ process.once('SIGTERM', this.onSignal.bind(this, 'SIGTERM'));
194
+ process.once('exit', this.onMasterExit.bind(this));
195
+ }
196
+ /**
197
+ * on bootstrap receive a exit signal
198
+ * @param signal
199
+ */
200
+ async onSignal(signal) {
201
+ if (!this.isClosing) {
202
+ this.options.logger.info('[bootstrap:master] receive signal %s, closing', signal);
203
+ try {
204
+ await this.stop();
205
+ this.options.logger.info('[bootstrap:master] close done, exiting with code:0');
206
+ process.exit(0);
207
+ }
208
+ catch (err) {
209
+ this.options.logger.error('[midway:master] close with error: ', err);
210
+ process.exit(1);
211
+ }
212
+ }
213
+ }
214
+ /**
215
+ * on bootstrap process exit
216
+ * @param code
217
+ */
218
+ onMasterExit(code) {
219
+ this.options.logger.info('[bootstrap:master] exit with code:%s', code);
220
+ }
180
221
  }
181
222
  exports.AbstractForkManager = AbstractForkManager;
182
223
  //# sourceMappingURL=base.js.map
@@ -4,7 +4,7 @@ import { AbstractForkManager } from './base';
4
4
  import { Worker } from 'worker_threads';
5
5
  export declare class ThreadManager extends AbstractForkManager<Worker, ThreadOptions> {
6
6
  readonly options: ThreadOptions;
7
- private exitListener;
7
+ private workerExitListener;
8
8
  constructor(options?: ThreadOptions);
9
9
  createWorker(): Worker;
10
10
  bindWorkerDisconnect(listener: (worker: Worker) => void): void;
@@ -33,7 +33,7 @@ class ThreadManager extends base_1.AbstractForkManager {
33
33
  this.options.logger.info('new worker thread, threadId = %s.', this.getWorkerId(w));
34
34
  }
35
35
  w.on('exit', code => {
36
- this.exitListener(w, code);
36
+ this.workerExitListener(w, code);
37
37
  });
38
38
  return w;
39
39
  }
@@ -41,7 +41,7 @@ class ThreadManager extends base_1.AbstractForkManager {
41
41
  // this.disconnectListener = listener;
42
42
  }
43
43
  bindWorkerExit(listener) {
44
- this.exitListener = listener;
44
+ this.workerExitListener = listener;
45
45
  }
46
46
  getWorkerId(worker) {
47
47
  return worker['_originThreadId'] || String(worker.threadId);
package/dist/sticky.js CHANGED
@@ -60,10 +60,11 @@ function setupStickyMaster(httpServer, opts = {}) {
60
60
  socket.destroy();
61
61
  }
62
62
  };
63
- socket.on('data', buffer => {
64
- const data = buffer.toString();
63
+ socket.on('data', (buffer) => {
64
+ let encoding = 'utf-8';
65
+ let data = buffer.toString(encoding);
65
66
  if (workerId && connectionId) {
66
- cluster.workers[workerId].send({ type: 'sticky:http-chunk', data, connectionId }, sendCallback);
67
+ cluster.workers[workerId].send({ type: 'sticky:http-chunk', data, encoding, connectionId }, sendCallback);
67
68
  return;
68
69
  }
69
70
  workerId = computeWorkerId(data);
@@ -71,11 +72,16 @@ function setupStickyMaster(httpServer, opts = {}) {
71
72
  data
72
73
  .substring(0, data.indexOf('\r\n\r\n'))
73
74
  .includes('pgrade: websocket'));
75
+ // avoid binary data toString error
76
+ if (data.startsWith('POST') && data.includes('multipart/form-data')) {
77
+ encoding = 'base64';
78
+ data = buffer.toString('base64');
79
+ }
74
80
  socket.pause();
75
81
  if (mayHaveMultipleChunks) {
76
82
  connectionId = randomId();
77
83
  }
78
- cluster.workers[workerId].send({ type: 'sticky:connection', data, connectionId }, socket, {
84
+ cluster.workers[workerId].send({ type: 'sticky:connection', data, encoding, connectionId }, socket, {
79
85
  keepOpen: mayHaveMultipleChunks,
80
86
  }, sendCallback);
81
87
  });
@@ -105,7 +111,7 @@ exports.setupStickyMaster = setupStickyMaster;
105
111
  function setupWorker(io) {
106
112
  // store connections that may receive multiple chunks
107
113
  const sockets = new Map();
108
- process.on('message', ({ type, data, connectionId }, socket) => {
114
+ process.on('message', ({ type, data, encoding, connectionId }, socket) => {
109
115
  switch (type) {
110
116
  case 'sticky:connection':
111
117
  if (!socket) {
@@ -114,7 +120,7 @@ function setupWorker(io) {
114
120
  return;
115
121
  }
116
122
  io.httpServer.emit('connection', socket); // inject connection
117
- socket.emit('data', Buffer.from(data)); // republish first chunk
123
+ socket.emit('data', Buffer.from(data, encoding)); // republish first chunk
118
124
  socket.resume();
119
125
  if (connectionId) {
120
126
  sockets.set(connectionId, socket);
@@ -126,7 +132,7 @@ function setupWorker(io) {
126
132
  case 'sticky:http-chunk': {
127
133
  const socket = sockets.get(connectionId);
128
134
  if (socket) {
129
- socket.emit('data', Buffer.from(data));
135
+ socket.emit('data', Buffer.from(data, encoding));
130
136
  }
131
137
  }
132
138
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midwayjs/bootstrap",
3
- "version": "3.9.0",
3
+ "version": "3.10.0",
4
4
  "description": "midwayjs bootstrap",
5
5
  "main": "dist/index",
6
6
  "typings": "dist/index.d.ts",
@@ -21,14 +21,14 @@
21
21
  ],
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "@midwayjs/async-hooks-context-manager": "^3.9.0",
24
+ "@midwayjs/async-hooks-context-manager": "^3.10.0",
25
25
  "@midwayjs/event-bus": "^1.0.1"
26
26
  },
27
27
  "devDependencies": {
28
- "@midwayjs/core": "^3.9.0",
28
+ "@midwayjs/core": "^3.10.0",
29
29
  "@midwayjs/logger": "^2.15.0",
30
30
  "request": "2.88.2",
31
- "socket.io-client": "4.5.3"
31
+ "socket.io-client": "4.5.4"
32
32
  },
33
33
  "author": "Harry Chen <czy88840616@gmail.com>",
34
34
  "repository": {
@@ -38,5 +38,5 @@
38
38
  "engines": {
39
39
  "node": ">=12.11.0"
40
40
  },
41
- "gitHead": "5f6603d2c9606fc6fc7ece71f956e89e394efeee"
41
+ "gitHead": "33d28f1a020963404488e866432916fd15c0952c"
42
42
  }