seyfert 5.1.0 → 5.1.1-dev-34481657717.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/lib/client/plugins/registry.js +2 -7
- package/lib/client/workerclient.d.ts +2 -1
- package/lib/client/workerclient.js +62 -25
- package/lib/common/it/utils.d.ts +4 -1
- package/lib/common/it/utils.js +14 -8
- package/lib/langs/handler.js +1 -4
- package/lib/websocket/discord/workermanager.d.ts +30 -17
- package/lib/websocket/discord/workermanager.js +138 -61
- package/package.json +1 -1
|
@@ -30,6 +30,7 @@ exports.installPluginMiddlewares = installPluginMiddlewares;
|
|
|
30
30
|
exports.resolveGatewayIntent = resolveGatewayIntent;
|
|
31
31
|
exports.unknownGatewayIntentBits = unknownGatewayIntentBits;
|
|
32
32
|
exports.validatePluginRequirements = validatePluginRequirements;
|
|
33
|
+
const utils_1 = require("../../common/it/utils");
|
|
33
34
|
const types_1 = require("../../types");
|
|
34
35
|
const api_1 = require("./api");
|
|
35
36
|
const errors_1 = require("./errors");
|
|
@@ -105,7 +106,7 @@ function createPluginRuntimeRegistry(plugins = []) {
|
|
|
105
106
|
function runPluginRegister(record, registry) {
|
|
106
107
|
try {
|
|
107
108
|
const result = record.plugin.register?.((0, api_1.createPluginApi)(record, registry));
|
|
108
|
-
if (isPromiseLike(result)) {
|
|
109
|
+
if ((0, utils_1.isPromiseLike)(result)) {
|
|
109
110
|
Promise.resolve(result).catch(() => undefined);
|
|
110
111
|
throw (0, errors_1.createPluginConflictError)(record.plugin.name, 'register', record.index, 'register(api) must be synchronous.', record.plugin.instanceId);
|
|
111
112
|
}
|
|
@@ -860,9 +861,3 @@ const reservedContextKeys = new Set([
|
|
|
860
861
|
function capitalize(value) {
|
|
861
862
|
return value[0]?.toUpperCase() + value.slice(1);
|
|
862
863
|
}
|
|
863
|
-
function isPromiseLike(value) {
|
|
864
|
-
return (typeof value === 'object' &&
|
|
865
|
-
value !== null &&
|
|
866
|
-
'then' in value &&
|
|
867
|
-
typeof value.then === 'function');
|
|
868
|
-
}
|
|
@@ -39,7 +39,7 @@ export declare class WorkerClient<Ready extends boolean = boolean> extends BaseC
|
|
|
39
39
|
get workerData(): WorkerData;
|
|
40
40
|
start(options?: Omit<DeepPartial<StartOptions>, 'httpConnection' | 'token' | 'connection'>): Promise<void>;
|
|
41
41
|
loadEvents(dir?: string): Promise<void>;
|
|
42
|
-
postMessage(body: WorkerMessages | ClientHeartbeaterMessages): unknown
|
|
42
|
+
postMessage(body: WorkerMessages | ClientHeartbeaterMessages): Promise<unknown>;
|
|
43
43
|
handleManagerMessages(data: ManagerMessages | WorkerHeartbeaterMessages): Promise<any>;
|
|
44
44
|
calculateShardId(guildId: string): number;
|
|
45
45
|
/**
|
|
@@ -51,6 +51,7 @@ export declare class WorkerClient<Ready extends boolean = boolean> extends BaseC
|
|
|
51
51
|
private sendGatewayPayloadOnShard;
|
|
52
52
|
private generateNonce;
|
|
53
53
|
private generateSendPromise;
|
|
54
|
+
private sendRequest;
|
|
54
55
|
tellWorker<R, V extends Record<string, unknown>>(workerId: number, func: (_: this, vars: V) => R, vars: V): Promise<R>;
|
|
55
56
|
tellWorkers<R, V extends Record<string, unknown>>(func: (_: this, vars: V) => R, vars: V): Promise<Awaited<R>[]>;
|
|
56
57
|
createShard(id: number, data: Pick<ManagerSpawnShards, 'info' | 'compress' | 'properties'>): Shard;
|
|
@@ -49,9 +49,6 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
49
49
|
resharding = new Map();
|
|
50
50
|
constructor(options) {
|
|
51
51
|
super(options);
|
|
52
|
-
if (options?.postMessage) {
|
|
53
|
-
this.postMessage = options.postMessage;
|
|
54
|
-
}
|
|
55
52
|
if (this.options.handleManagerMessages) {
|
|
56
53
|
const oldFn = this.handleManagerMessages.bind(this);
|
|
57
54
|
this.handleManagerMessages = async (message) => {
|
|
@@ -102,7 +99,11 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
102
99
|
manager = worker_threads?.parentPort;
|
|
103
100
|
}
|
|
104
101
|
if (workerData.mode !== 'custom')
|
|
105
|
-
(manager ?? process).on('message', (data) =>
|
|
102
|
+
(manager ?? process).on('message', (data) => {
|
|
103
|
+
void this.handleManagerMessages(data).catch(error => {
|
|
104
|
+
this.logger.error('Worker manager message handling failed', error);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
106
107
|
this.configureLogger({ name: `[Worker #${workerData.workerId}]` }, this.options.logger);
|
|
107
108
|
if (workerData.debug) {
|
|
108
109
|
this.debugger = new __1.Logger({
|
|
@@ -123,7 +124,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
123
124
|
this.rest.workerData = workerData;
|
|
124
125
|
await super.start(options);
|
|
125
126
|
workerData.intents = this.resolvePluginGatewayIntents(workerData.intents);
|
|
126
|
-
this.postMessage({
|
|
127
|
+
await this.postMessage({
|
|
127
128
|
type: workerData.resharding ? 'WORKER_START_RESHARDING' : 'WORKER_START',
|
|
128
129
|
workerId: workerData.workerId,
|
|
129
130
|
});
|
|
@@ -138,15 +139,24 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
138
139
|
}
|
|
139
140
|
await (0, plugins_1.runPluginHooks)(this, 'events:afterLoad', this, dir);
|
|
140
141
|
}
|
|
141
|
-
postMessage(body) {
|
|
142
|
+
async postMessage(body) {
|
|
143
|
+
if (this.options.postMessage)
|
|
144
|
+
return this.options.postMessage.call(this, body);
|
|
142
145
|
if (manager)
|
|
143
146
|
return manager.postMessage(body);
|
|
144
|
-
return
|
|
147
|
+
return new Promise((resolve, reject) => {
|
|
148
|
+
process.send(body, error => {
|
|
149
|
+
if (error)
|
|
150
|
+
reject(error);
|
|
151
|
+
else
|
|
152
|
+
resolve();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
145
155
|
}
|
|
146
156
|
async handleManagerMessages(data) {
|
|
147
157
|
switch (data.type) {
|
|
148
158
|
case 'HEARTBEAT':
|
|
149
|
-
this.postMessage({
|
|
159
|
+
await this.postMessage({
|
|
150
160
|
type: 'ACK_HEARTBEAT',
|
|
151
161
|
workerId: workerData.workerId,
|
|
152
162
|
});
|
|
@@ -170,7 +180,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
170
180
|
this.logger.fatal(`Worker trying to send payload by non-existent shard (#${data.shardId})`);
|
|
171
181
|
return;
|
|
172
182
|
}
|
|
173
|
-
this.postMessage({
|
|
183
|
+
await this.postMessage({
|
|
174
184
|
type: 'RESULT_PAYLOAD',
|
|
175
185
|
nonce: data.nonce,
|
|
176
186
|
workerId: this.workerId,
|
|
@@ -225,15 +235,19 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
225
235
|
if (payload.t !== types_1.GatewayDispatchEvents.GuildsReady)
|
|
226
236
|
return;
|
|
227
237
|
if (++shardsConnected === workerData.shards.length) {
|
|
228
|
-
self
|
|
238
|
+
void self
|
|
239
|
+
.postMessage({
|
|
229
240
|
type: 'WORKER_READY_RESHARDING',
|
|
230
241
|
workerId: workerData.workerId,
|
|
242
|
+
})
|
|
243
|
+
.catch(error => {
|
|
244
|
+
self.logger.error('Failed to send WORKER_READY_RESHARDING to the worker manager', error);
|
|
231
245
|
});
|
|
232
246
|
}
|
|
233
247
|
},
|
|
234
248
|
});
|
|
235
249
|
this.resharding.set(id, shard);
|
|
236
|
-
this.postMessage({
|
|
250
|
+
await this.postMessage({
|
|
237
251
|
type: 'CONNECT_QUEUE_RESHARDING',
|
|
238
252
|
shardId: id,
|
|
239
253
|
workerId: workerData.workerId,
|
|
@@ -251,7 +265,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
251
265
|
}
|
|
252
266
|
const shard = this.createShard(id, data);
|
|
253
267
|
this.shards.set(id, shard);
|
|
254
|
-
this.postMessage({
|
|
268
|
+
await this.postMessage({
|
|
255
269
|
type: 'CONNECT_QUEUE',
|
|
256
270
|
shardId: id,
|
|
257
271
|
workerId: workerData.workerId,
|
|
@@ -266,7 +280,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
266
280
|
this.logger.fatal(`Worker trying to get non-existent shard (#${data.shardId})`);
|
|
267
281
|
return;
|
|
268
282
|
}
|
|
269
|
-
this.postMessage({
|
|
283
|
+
await this.postMessage({
|
|
270
284
|
...generateShardInfo(shard),
|
|
271
285
|
nonce: data.nonce,
|
|
272
286
|
type: 'SHARD_INFO',
|
|
@@ -276,7 +290,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
276
290
|
break;
|
|
277
291
|
case 'WORKER_INFO':
|
|
278
292
|
{
|
|
279
|
-
this.postMessage({
|
|
293
|
+
await this.postMessage({
|
|
280
294
|
shards: [...this.shards.values()].map(generateShardInfo),
|
|
281
295
|
workerId: workerData.workerId,
|
|
282
296
|
type: 'WORKER_INFO',
|
|
@@ -310,7 +324,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
310
324
|
catch (e) {
|
|
311
325
|
result = e;
|
|
312
326
|
}
|
|
313
|
-
this.postMessage({
|
|
327
|
+
await this.postMessage({
|
|
314
328
|
type: 'EVAL_RESPONSE',
|
|
315
329
|
response: result,
|
|
316
330
|
workerId: workerData.workerId,
|
|
@@ -330,7 +344,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
330
344
|
break;
|
|
331
345
|
case 'WORKER_ALREADY_EXISTS_RESHARDING':
|
|
332
346
|
{
|
|
333
|
-
this.postMessage({
|
|
347
|
+
await this.postMessage({
|
|
334
348
|
type: 'WORKER_START_RESHARDING',
|
|
335
349
|
workerId: workerData.workerId,
|
|
336
350
|
});
|
|
@@ -341,7 +355,7 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
341
355
|
for (const i of this.shards.values()) {
|
|
342
356
|
await i.disconnect(websocket_1.ShardSocketCloseCodes.Resharding);
|
|
343
357
|
}
|
|
344
|
-
this.postMessage({
|
|
358
|
+
await this.postMessage({
|
|
345
359
|
type: 'DISCONNECTED_ALL_SHARDS_RESHARDING',
|
|
346
360
|
workerId: workerData.workerId,
|
|
347
361
|
});
|
|
@@ -407,17 +421,31 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
407
421
|
this.promises.set(nonce, { resolve: res, timeout });
|
|
408
422
|
});
|
|
409
423
|
}
|
|
410
|
-
|
|
424
|
+
async sendRequest(nonce, operation, send) {
|
|
425
|
+
const response = this.generateSendPromise(nonce, operation);
|
|
426
|
+
try {
|
|
427
|
+
const [result] = await Promise.all([response, send()]);
|
|
428
|
+
return result;
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
const pending = this.promises.get(nonce);
|
|
432
|
+
if (pending) {
|
|
433
|
+
this.promises.delete(nonce);
|
|
434
|
+
clearTimeout(pending.timeout);
|
|
435
|
+
}
|
|
436
|
+
throw error;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
async tellWorker(workerId, func, vars) {
|
|
411
440
|
const nonce = this.generateNonce();
|
|
412
|
-
this.postMessage({
|
|
441
|
+
return this.sendRequest(nonce, 'Worker request', () => this.postMessage({
|
|
413
442
|
type: 'EVAL_TO_WORKER',
|
|
414
443
|
func: func.toString(),
|
|
415
444
|
toWorkerId: workerId,
|
|
416
445
|
workerId: workerData.workerId,
|
|
417
446
|
nonce,
|
|
418
447
|
vars: JSON.stringify(vars),
|
|
419
|
-
});
|
|
420
|
-
return this.generateSendPromise(nonce);
|
|
448
|
+
}));
|
|
421
449
|
}
|
|
422
450
|
tellWorkers(func, vars) {
|
|
423
451
|
const promises = [];
|
|
@@ -446,13 +474,18 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
446
474
|
async handlePayload(shardId, payload) {
|
|
447
475
|
await handlePayload?.(shardId, payload);
|
|
448
476
|
const pluginPacket = await onPacket(payload, shardId);
|
|
449
|
-
if (self.options.sendPayloadToParent && pluginPacket !== null)
|
|
450
|
-
self
|
|
477
|
+
if (self.options.sendPayloadToParent && pluginPacket !== null) {
|
|
478
|
+
void self
|
|
479
|
+
.postMessage({
|
|
451
480
|
workerId: workerData.workerId,
|
|
452
481
|
shardId,
|
|
453
482
|
type: 'RECEIVE_PAYLOAD',
|
|
454
483
|
payload: pluginPacket,
|
|
484
|
+
})
|
|
485
|
+
.catch(error => {
|
|
486
|
+
self.logger.error('Failed to send RECEIVE_PAYLOAD to the worker manager', error);
|
|
455
487
|
});
|
|
488
|
+
}
|
|
456
489
|
},
|
|
457
490
|
});
|
|
458
491
|
return shard;
|
|
@@ -522,9 +555,11 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
522
555
|
this.applicationId = packet.d.application.id;
|
|
523
556
|
this.me = transformers_1.Transformers.ClientUser(this, packet.d.user, packet.d.application);
|
|
524
557
|
if ([...this.shards.values()].every(shard => shard.data.session_id)) {
|
|
525
|
-
this.postMessage({
|
|
558
|
+
void this.postMessage({
|
|
526
559
|
type: 'WORKER_SHARDS_CONNECTED',
|
|
527
560
|
workerId: this.workerId,
|
|
561
|
+
}).catch(error => {
|
|
562
|
+
this.logger.error('Failed to send WORKER_SHARDS_CONNECTED to the worker manager', error);
|
|
528
563
|
});
|
|
529
564
|
await this.events.runEvent('WORKER_SHARDS_CONNECTED', this, this.me, -1);
|
|
530
565
|
}
|
|
@@ -535,9 +570,11 @@ class WorkerClient extends base_1.BaseClient {
|
|
|
535
570
|
case types_1.GatewayDispatchEvents.GuildsReady:
|
|
536
571
|
{
|
|
537
572
|
if ([...this.shards.values()].every(shard => shard.isReady)) {
|
|
538
|
-
this.postMessage({
|
|
573
|
+
void this.postMessage({
|
|
539
574
|
type: 'WORKER_READY',
|
|
540
575
|
workerId: this.workerId,
|
|
576
|
+
}).catch(error => {
|
|
577
|
+
this.logger.error('Failed to send WORKER_READY to the worker manager', error);
|
|
541
578
|
});
|
|
542
579
|
await this.events.runEvent('WORKER_READY', this, this.me, -1);
|
|
543
580
|
}
|
package/lib/common/it/utils.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Cache } from '../../cache';
|
|
2
2
|
import { type APIPartialEmoji, GatewayIntentBits } from '../../types';
|
|
3
|
+
import type { ColorResolvable, EmojiResolvable } from '../types/resolvables';
|
|
4
|
+
import type { ObjectToLower, ObjectToSnake, TypeArray } from '../types/util';
|
|
5
|
+
import type { Logger } from './logger';
|
|
3
6
|
export { type FakePromiseResult, fakePromise } from './fake-promise';
|
|
4
|
-
import { type ColorResolvable, type EmojiResolvable, type Logger, type ObjectToLower, type ObjectToSnake, type TypeArray } from '..';
|
|
5
7
|
/**
|
|
6
8
|
* Calculates the shard ID for a guild based on its ID.
|
|
7
9
|
* @param guildId The ID of the guild.
|
|
@@ -28,6 +30,7 @@ export declare function delay<T>(time: number, result?: T): Promise<T>;
|
|
|
28
30
|
* @returns `true` if the value is an object, otherwise `false`.
|
|
29
31
|
*/
|
|
30
32
|
export declare function isObject(o: any): o is Record<string, unknown>;
|
|
33
|
+
export declare function isPromiseLike<T>(value: T | PromiseLike<T>): value is PromiseLike<T>;
|
|
31
34
|
/**
|
|
32
35
|
* Merges multiple options objects together, deeply extending objects.
|
|
33
36
|
* @param defaults The default options object.
|
package/lib/common/it/utils.js
CHANGED
|
@@ -5,6 +5,7 @@ exports.calculateShardId = calculateShardId;
|
|
|
5
5
|
exports.resolveColor = resolveColor;
|
|
6
6
|
exports.delay = delay;
|
|
7
7
|
exports.isObject = isObject;
|
|
8
|
+
exports.isPromiseLike = isPromiseLike;
|
|
8
9
|
exports.MergeOptions = MergeOptions;
|
|
9
10
|
exports.filterSplit = filterSplit;
|
|
10
11
|
exports.toSnakeCase = toSnakeCase;
|
|
@@ -24,9 +25,10 @@ exports.assertString = assertString;
|
|
|
24
25
|
const node_fs_1 = require("node:fs");
|
|
25
26
|
const node_path_1 = require("node:path");
|
|
26
27
|
const types_1 = require("../../types");
|
|
28
|
+
const constants_1 = require("./constants");
|
|
29
|
+
const error_1 = require("./error");
|
|
27
30
|
var fake_promise_1 = require("./fake-promise");
|
|
28
31
|
Object.defineProperty(exports, "fakePromise", { enumerable: true, get: function () { return fake_promise_1.fakePromise; } });
|
|
29
|
-
const __1 = require("..");
|
|
30
32
|
/**
|
|
31
33
|
* Calculates the shard ID for a guild based on its ID.
|
|
32
34
|
* @param guildId The ID of the guild.
|
|
@@ -39,7 +41,7 @@ function calculateShardId(guildId, shards) {
|
|
|
39
41
|
// It is used for resolve color for better performance
|
|
40
42
|
const ColorLookup = {
|
|
41
43
|
Random: -1, // Special value for random color
|
|
42
|
-
...
|
|
44
|
+
...constants_1.EmbedColors,
|
|
43
45
|
};
|
|
44
46
|
/**
|
|
45
47
|
* Resolves the color to a numeric representation.
|
|
@@ -50,7 +52,7 @@ function resolveColor(color) {
|
|
|
50
52
|
const type = typeof color;
|
|
51
53
|
if (type === 'number') {
|
|
52
54
|
if (!Number.isInteger(color) || color < 0)
|
|
53
|
-
throw new
|
|
55
|
+
throw new error_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `Invalid color: ${color}` } });
|
|
54
56
|
return color;
|
|
55
57
|
}
|
|
56
58
|
if (type === 'string') {
|
|
@@ -61,14 +63,14 @@ function resolveColor(color) {
|
|
|
61
63
|
if (color.startsWith('#')) {
|
|
62
64
|
const hex = color.slice(1);
|
|
63
65
|
if (!/^[\da-f]+$/i.test(hex))
|
|
64
|
-
throw new
|
|
66
|
+
throw new error_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: `Invalid color: ${color}` } });
|
|
65
67
|
return Number.parseInt(hex, 16);
|
|
66
68
|
}
|
|
67
|
-
return
|
|
69
|
+
return constants_1.EmbedColors.Default;
|
|
68
70
|
}
|
|
69
71
|
return Array.isArray(color) && color.length >= 3
|
|
70
72
|
? (color[0] << 16) | (color[1] << 8) | color[2]
|
|
71
|
-
:
|
|
73
|
+
: constants_1.EmbedColors.Default;
|
|
72
74
|
}
|
|
73
75
|
/**
|
|
74
76
|
* Delays the resolution of a Promise by the specified time.
|
|
@@ -87,6 +89,10 @@ function delay(time, result) {
|
|
|
87
89
|
function isObject(o) {
|
|
88
90
|
return o && typeof o === 'object' && !Array.isArray(o);
|
|
89
91
|
}
|
|
92
|
+
function isPromiseLike(value) {
|
|
93
|
+
return (((typeof value === 'object' && value !== null) || typeof value === 'function') &&
|
|
94
|
+
typeof value.then === 'function');
|
|
95
|
+
}
|
|
90
96
|
function isPlainObject(o) {
|
|
91
97
|
if (!o || typeof o !== 'object')
|
|
92
98
|
return false;
|
|
@@ -301,7 +307,7 @@ function isCloudflareWorker() {
|
|
|
301
307
|
* @returns The unix millisecond timestamp.
|
|
302
308
|
*/
|
|
303
309
|
function snowflakeToTimestamp(id) {
|
|
304
|
-
return Number((BigInt(id) >> 22n) +
|
|
310
|
+
return Number((BigInt(id) >> 22n) + constants_1.DiscordEpoch);
|
|
305
311
|
}
|
|
306
312
|
function resolvePartialEmoji(emoji) {
|
|
307
313
|
if (typeof emoji === 'string') {
|
|
@@ -383,6 +389,6 @@ function toBuffer(arrayBuffer) {
|
|
|
383
389
|
}
|
|
384
390
|
function assertString(value, message) {
|
|
385
391
|
if (!(typeof value === 'string' && value !== '')) {
|
|
386
|
-
throw new
|
|
392
|
+
throw new error_1.SeyfertError('INTERNAL_ERROR', { metadata: { detail: message ?? 'Value is not a string' } });
|
|
387
393
|
}
|
|
388
394
|
}
|
package/lib/langs/handler.js
CHANGED
|
@@ -4,9 +4,6 @@ exports.LangsHandler = void 0;
|
|
|
4
4
|
const node_path_1 = require("node:path");
|
|
5
5
|
const common_1 = require("../common");
|
|
6
6
|
const router_1 = require("./router");
|
|
7
|
-
function isPromiseLike(value) {
|
|
8
|
-
return !!value && typeof value.then === 'function';
|
|
9
|
-
}
|
|
10
7
|
class LangsHandler extends common_1.BaseHandler {
|
|
11
8
|
values = {};
|
|
12
9
|
__paths = {};
|
|
@@ -46,7 +43,7 @@ class LangsHandler extends common_1.BaseHandler {
|
|
|
46
43
|
parse(file) {
|
|
47
44
|
const oldLocale = file.name.split('.').slice(0, -1).join('.') || file.name;
|
|
48
45
|
const result = this.onFile(oldLocale, file);
|
|
49
|
-
if (isPromiseLike(result))
|
|
46
|
+
if ((0, common_1.isPromiseLike)(result))
|
|
50
47
|
return result.then(value => this.applyParsedFile(file, value));
|
|
51
48
|
this.applyParsedFile(file, result);
|
|
52
49
|
return;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type Worker as ClusterWorker } from 'node:cluster';
|
|
2
2
|
import type { Worker as WorkerThreadsWorker } from 'node:worker_threads';
|
|
3
3
|
import { ApiHandler, type CustomWorkerManagerEvents, Logger, type UsingClient, type WorkerClient } from '../..';
|
|
4
4
|
import { type Adapter } from '../../cache';
|
|
5
|
-
import { type Identify, type PickPartial } from '../../common';
|
|
5
|
+
import { type Awaitable, type Identify, type PickPartial } from '../../common';
|
|
6
6
|
import type { GatewayPresenceUpdateData, GatewaySendPayload } from '../../types';
|
|
7
7
|
import { ConnectQueue } from '../structures/timeout';
|
|
8
8
|
import { Heartbeater, type WorkerHeartbeaterMessages } from './heartbeater';
|
|
@@ -23,13 +23,18 @@ type WorkerManagerCustomRuntimeOptionalKeys = 'handleWorkerMessage' | 'handlePay
|
|
|
23
23
|
type WorkerManagerRuntimeOptions = PickPartial<Required<WorkerManagerNativeOptions>, WorkerManagerRuntimeOptionalKeys> | (PickPartial<Required<Omit<WorkerManagerCustomOptions, 'path'>>, WorkerManagerCustomRuntimeOptionalKeys> & {
|
|
24
24
|
path?: string;
|
|
25
25
|
});
|
|
26
|
-
|
|
27
|
-
ready?: boolean;
|
|
28
|
-
}) & {
|
|
26
|
+
type WorkerState = {
|
|
29
27
|
ready?: boolean;
|
|
30
28
|
disconnected?: boolean;
|
|
31
29
|
resharded?: boolean;
|
|
32
|
-
}
|
|
30
|
+
};
|
|
31
|
+
type CustomWorker = {
|
|
32
|
+
ready?: boolean;
|
|
33
|
+
} & WorkerState;
|
|
34
|
+
type ManagedWorker = (ClusterWorker | WorkerThreadsWorker | {
|
|
35
|
+
ready?: boolean;
|
|
36
|
+
}) & WorkerState;
|
|
37
|
+
export declare class WorkerManager extends Map<number, ManagedWorker> {
|
|
33
38
|
static prepareSpaces(options: {
|
|
34
39
|
shardStart: number;
|
|
35
40
|
shardEnd: number;
|
|
@@ -38,17 +43,19 @@ export declare class WorkerManager extends Map<number, (ClusterWorker | WorkerTh
|
|
|
38
43
|
options: WorkerManagerRuntimeOptions;
|
|
39
44
|
debugger?: Logger;
|
|
40
45
|
connectQueue: ConnectQueue;
|
|
41
|
-
workerQueue: (() => void)[];
|
|
46
|
+
workerQueue: (() => Awaitable<void>)[];
|
|
42
47
|
cacheAdapter: Adapter;
|
|
43
48
|
promises: Map<string, {
|
|
44
49
|
resolve: (value: any) => void;
|
|
45
50
|
timeout: NodeJS.Timeout;
|
|
46
51
|
}>;
|
|
47
52
|
rest: ApiHandler;
|
|
48
|
-
reshardingWorkerQueue: (() => void)[];
|
|
53
|
+
reshardingWorkerQueue: (() => Awaitable<void>)[];
|
|
49
54
|
private _info?;
|
|
50
55
|
heartbeater: Heartbeater;
|
|
51
56
|
constructor(options: WorkerManagerConstructorOptions);
|
|
57
|
+
private reportError;
|
|
58
|
+
private observe;
|
|
52
59
|
setCache(adapter: Adapter): void;
|
|
53
60
|
setRest(rest: ApiHandler): void;
|
|
54
61
|
get remaining(): number;
|
|
@@ -68,19 +75,25 @@ export declare class WorkerManager extends Map<number, (ClusterWorker | WorkerTh
|
|
|
68
75
|
calculateShardId(guildId: string): number;
|
|
69
76
|
private createWorkerNotFoundError;
|
|
70
77
|
calculateWorkerId(shardId: number): number;
|
|
71
|
-
postMessage(id: number, body: ManagerMessages | WorkerHeartbeaterMessages): void
|
|
78
|
+
postMessage(id: number, body: ManagerMessages | WorkerHeartbeaterMessages): Promise<void>;
|
|
72
79
|
prepareWorkers(shards: number[][], rawResharding?: boolean): void;
|
|
73
|
-
createWorker(workerData: WorkerData
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
createWorker(workerData: WorkerData & {
|
|
81
|
+
mode: 'threads';
|
|
82
|
+
}): WorkerThreadsWorker;
|
|
83
|
+
createWorker(workerData: WorkerData & {
|
|
84
|
+
mode: 'clusters';
|
|
85
|
+
}): ClusterWorker;
|
|
86
|
+
createWorker(workerData: WorkerData & {
|
|
87
|
+
mode: 'custom';
|
|
88
|
+
}): Awaitable<CustomWorker>;
|
|
89
|
+
createWorker(workerData: WorkerData): Awaitable<ManagedWorker>;
|
|
90
|
+
private createWorkerAsync;
|
|
91
|
+
private createWorkerInternal;
|
|
92
|
+
spawn(workerId: number, shardId: number, resharding?: boolean): Promise<void>;
|
|
81
93
|
handleWorkerMessage(message: WorkerMessages): Promise<void>;
|
|
82
94
|
private generateNonce;
|
|
83
95
|
private generateSendPromise;
|
|
96
|
+
private sendRequest;
|
|
84
97
|
send(data: GatewaySendPayload, shardId: number): Promise<boolean>;
|
|
85
98
|
private resolveSendPayload;
|
|
86
99
|
getShardInfo(shardId: number): Promise<WorkerShardInfo>;
|
|
@@ -51,7 +51,23 @@ class WorkerManager extends Map {
|
|
|
51
51
|
return oldFn(message);
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
this.heartbeater = new heartbeater_1.Heartbeater(
|
|
54
|
+
this.heartbeater = new heartbeater_1.Heartbeater((workerId, message) => {
|
|
55
|
+
this.observe(() => this.postMessage(workerId, message), `[Worker #${workerId}] heartbeat sending failed`);
|
|
56
|
+
}, options.heartbeaterInterval ?? 15e3);
|
|
57
|
+
}
|
|
58
|
+
reportError(message, error) {
|
|
59
|
+
this.debugger ??= new __1.Logger({ name: '[WorkerManager]' });
|
|
60
|
+
this.debugger.error(message, error);
|
|
61
|
+
}
|
|
62
|
+
observe(operation, message) {
|
|
63
|
+
try {
|
|
64
|
+
void Promise.resolve(operation()).catch(error => {
|
|
65
|
+
this.reportError(message, error);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
this.reportError(message, error);
|
|
70
|
+
}
|
|
55
71
|
}
|
|
56
72
|
setCache(adapter) {
|
|
57
73
|
this.cacheAdapter = adapter;
|
|
@@ -118,21 +134,37 @@ class WorkerManager extends Map {
|
|
|
118
134
|
}
|
|
119
135
|
return Math.floor((shardId - minimumShardId) / this.shardsPerWorker);
|
|
120
136
|
}
|
|
121
|
-
postMessage(id, body) {
|
|
137
|
+
async postMessage(id, body) {
|
|
122
138
|
const worker = this.get(id);
|
|
123
139
|
if (!worker)
|
|
124
|
-
|
|
140
|
+
throw this.createWorkerNotFoundError(id);
|
|
125
141
|
switch (this.options.mode) {
|
|
126
|
-
case 'clusters':
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
142
|
+
case 'clusters': {
|
|
143
|
+
const clusterWorker = worker;
|
|
144
|
+
if (!clusterWorker.isConnected()) {
|
|
145
|
+
throw new common_1.SeyfertError('INTERNAL_ERROR', {
|
|
146
|
+
metadata: {
|
|
147
|
+
workerId: id,
|
|
148
|
+
mode: this.options.mode,
|
|
149
|
+
detail: `Cannot send to disconnected worker #${id}.`,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
await new Promise((resolve, reject) => {
|
|
154
|
+
clusterWorker.send(body, error => {
|
|
155
|
+
if (error)
|
|
156
|
+
reject(error);
|
|
157
|
+
else
|
|
158
|
+
resolve();
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
130
163
|
case 'threads':
|
|
131
164
|
worker.postMessage(body);
|
|
132
|
-
|
|
165
|
+
return;
|
|
133
166
|
case 'custom':
|
|
134
|
-
this.options.adapter.postMessage(id, body);
|
|
135
|
-
break;
|
|
167
|
+
await this.options.adapter.postMessage(id, body);
|
|
136
168
|
}
|
|
137
169
|
}
|
|
138
170
|
prepareWorkers(shards, rawResharding = false) {
|
|
@@ -142,8 +174,8 @@ class WorkerManager extends Map {
|
|
|
142
174
|
metadata: { detail: 'Cannot prepare workers without worker_threads.' },
|
|
143
175
|
});
|
|
144
176
|
for (let i = 0; i < shards.length; i++) {
|
|
145
|
-
const registerWorker = (resharding) => {
|
|
146
|
-
const worker = this.
|
|
177
|
+
const registerWorker = async (resharding) => {
|
|
178
|
+
const worker = await this.createWorkerAsync({
|
|
147
179
|
path: this.options.path ?? '',
|
|
148
180
|
debug: this.options.debug,
|
|
149
181
|
token: this.options.token,
|
|
@@ -168,25 +200,39 @@ class WorkerManager extends Map {
|
|
|
168
200
|
this.heartbeater.register(workerId, deadWorkerId => {
|
|
169
201
|
this.heartbeater.unregister(deadWorkerId);
|
|
170
202
|
this.delete(deadWorkerId);
|
|
171
|
-
|
|
203
|
+
this.observe(() => registerWorker(resharding).then(newWorkerId => registerWorkerHeartbeat(newWorkerId, resharding)), `[Worker #${deadWorkerId}] replacement failed`);
|
|
172
204
|
});
|
|
173
205
|
};
|
|
174
206
|
const workerExists = this.has(i);
|
|
175
207
|
if (rawResharding || !workerExists) {
|
|
176
|
-
this[rawResharding ? 'reshardingWorkerQueue' : 'workerQueue'].push(() => {
|
|
177
|
-
registerWorkerHeartbeat(registerWorker(rawResharding), rawResharding);
|
|
208
|
+
this[rawResharding ? 'reshardingWorkerQueue' : 'workerQueue'].push(async () => {
|
|
209
|
+
registerWorkerHeartbeat(await registerWorker(rawResharding), rawResharding);
|
|
178
210
|
});
|
|
179
211
|
}
|
|
180
212
|
}
|
|
181
213
|
}
|
|
182
214
|
createWorker(workerData) {
|
|
215
|
+
return this.createWorkerInternal(workerData);
|
|
216
|
+
}
|
|
217
|
+
createWorkerAsync(workerData) {
|
|
218
|
+
return Promise.resolve(this.createWorkerInternal(workerData));
|
|
219
|
+
}
|
|
220
|
+
createWorkerInternal(workerData) {
|
|
221
|
+
if (workerData.mode !== this.options.mode) {
|
|
222
|
+
throw new common_1.SeyfertError('INTERNAL_ERROR', {
|
|
223
|
+
metadata: {
|
|
224
|
+
workerId: workerData.workerId,
|
|
225
|
+
detail: `Worker mode ${workerData.mode} does not match manager mode ${this.options.mode}.`,
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
}
|
|
183
229
|
if (this.has(workerData.workerId)) {
|
|
230
|
+
const worker = this.get(workerData.workerId);
|
|
184
231
|
if (workerData.resharding) {
|
|
185
|
-
this.postMessage(workerData.workerId, {
|
|
232
|
+
this.observe(() => this.postMessage(workerData.workerId, {
|
|
186
233
|
type: 'WORKER_ALREADY_EXISTS_RESHARDING',
|
|
187
|
-
});
|
|
234
|
+
}), `[Worker #${workerData.workerId}] resharding restart message sending failed`);
|
|
188
235
|
}
|
|
189
|
-
const worker = this.get(workerData.workerId);
|
|
190
236
|
return worker;
|
|
191
237
|
}
|
|
192
238
|
const worker_threads = (0, common_1.lazyLoadPackage)('node:worker_threads');
|
|
@@ -209,7 +255,7 @@ class WorkerManager extends Map {
|
|
|
209
255
|
const worker = new worker_threads.Worker(workerData.path, {
|
|
210
256
|
env: { ...process.env, ...env },
|
|
211
257
|
});
|
|
212
|
-
worker.on('message', data => this.handleWorkerMessage(data));
|
|
258
|
+
worker.on('message', data => this.observe(() => this.handleWorkerMessage(data), `[Worker #${workerData.workerId}] message handling failed`));
|
|
213
259
|
worker.on('error', err => {
|
|
214
260
|
this.debugger?.error(`[Worker #${workerData.workerId}]`, err);
|
|
215
261
|
});
|
|
@@ -220,28 +266,46 @@ class WorkerManager extends Map {
|
|
|
220
266
|
exec: workerData.path,
|
|
221
267
|
});
|
|
222
268
|
const worker = node_cluster_1.default.fork(env);
|
|
223
|
-
worker.on('message', data => this.handleWorkerMessage(data));
|
|
269
|
+
worker.on('message', data => this.observe(() => this.handleWorkerMessage(data), `[Worker #${workerData.workerId}] message handling failed`));
|
|
224
270
|
return worker;
|
|
225
271
|
}
|
|
226
272
|
case 'custom': {
|
|
227
|
-
|
|
228
|
-
return {
|
|
273
|
+
const worker = {
|
|
229
274
|
ready: false,
|
|
230
275
|
};
|
|
276
|
+
this.set(workerData.workerId, worker);
|
|
277
|
+
try {
|
|
278
|
+
const spawnResult = this.options.adapter.spawn(workerData, env);
|
|
279
|
+
if (!(0, common_1.isPromiseLike)(spawnResult))
|
|
280
|
+
return worker;
|
|
281
|
+
return Promise.resolve(spawnResult).then(() => worker, error => {
|
|
282
|
+
if (this.get(workerData.workerId) === worker)
|
|
283
|
+
this.delete(workerData.workerId);
|
|
284
|
+
throw error;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
if (this.get(workerData.workerId) === worker)
|
|
289
|
+
this.delete(workerData.workerId);
|
|
290
|
+
throw error;
|
|
291
|
+
}
|
|
231
292
|
}
|
|
232
293
|
}
|
|
233
294
|
}
|
|
234
295
|
spawn(workerId, shardId, resharding = false) {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
296
|
+
return new Promise((resolve, reject) => {
|
|
297
|
+
this.connectQueue.push(() => {
|
|
298
|
+
if (!this.has(workerId)) {
|
|
299
|
+
const error = this.createWorkerNotFoundError(workerId);
|
|
300
|
+
this.debugger?.fatal(`Trying ${resharding ? 'reshard' : 'spawn'} with worker that doesn't exist`);
|
|
301
|
+
reject(error);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
void this.postMessage(workerId, {
|
|
305
|
+
type: resharding ? 'ALLOW_CONNECT_RESHARDING' : 'ALLOW_CONNECT',
|
|
306
|
+
shardId,
|
|
307
|
+
presence: this.options.presence?.(shardId, workerId),
|
|
308
|
+
}).then(resolve, reject);
|
|
245
309
|
});
|
|
246
310
|
});
|
|
247
311
|
}
|
|
@@ -255,7 +319,7 @@ class WorkerManager extends Map {
|
|
|
255
319
|
this.get(message.workerId).resharded = true;
|
|
256
320
|
if (!this.reshardingWorkerQueue.length && [...this.values()].every(w => w.resharded)) {
|
|
257
321
|
for (const [id] of this.entries()) {
|
|
258
|
-
this.postMessage(id, {
|
|
322
|
+
await this.postMessage(id, {
|
|
259
323
|
type: 'DISCONNECT_ALL_SHARDS_RESHARDING',
|
|
260
324
|
});
|
|
261
325
|
}
|
|
@@ -267,7 +331,7 @@ class WorkerManager extends Map {
|
|
|
267
331
|
const nextWorker = this.reshardingWorkerQueue.shift();
|
|
268
332
|
if (nextWorker) {
|
|
269
333
|
this.debugger?.info('Spawning next worker to reshard');
|
|
270
|
-
nextWorker
|
|
334
|
+
this.observe(nextWorker, 'Resharding worker spawn failed');
|
|
271
335
|
}
|
|
272
336
|
else {
|
|
273
337
|
this.debugger?.info('No more workers to reshard left');
|
|
@@ -284,7 +348,7 @@ class WorkerManager extends Map {
|
|
|
284
348
|
this.options.workers = this.size;
|
|
285
349
|
delete this._info;
|
|
286
350
|
for (const [id] of this.entries()) {
|
|
287
|
-
this.postMessage(id, {
|
|
351
|
+
await this.postMessage(id, {
|
|
288
352
|
type: 'CONNECT_ALL_SHARDS_RESHARDING',
|
|
289
353
|
totalShards: this.options.totalShards,
|
|
290
354
|
});
|
|
@@ -297,7 +361,7 @@ class WorkerManager extends Map {
|
|
|
297
361
|
break;
|
|
298
362
|
case 'WORKER_START_RESHARDING':
|
|
299
363
|
{
|
|
300
|
-
this.postMessage(message.workerId, {
|
|
364
|
+
await this.postMessage(message.workerId, {
|
|
301
365
|
type: 'SPAWN_SHARDS_RESHARDING',
|
|
302
366
|
compress: this.options.compress ?? false,
|
|
303
367
|
info: {
|
|
@@ -313,7 +377,7 @@ class WorkerManager extends Map {
|
|
|
313
377
|
break;
|
|
314
378
|
case 'WORKER_START':
|
|
315
379
|
{
|
|
316
|
-
this.postMessage(message.workerId, {
|
|
380
|
+
await this.postMessage(message.workerId, {
|
|
317
381
|
type: 'SPAWN_SHARDS',
|
|
318
382
|
compress: this.options.compress ?? false,
|
|
319
383
|
info: {
|
|
@@ -328,10 +392,10 @@ class WorkerManager extends Map {
|
|
|
328
392
|
}
|
|
329
393
|
break;
|
|
330
394
|
case 'CONNECT_QUEUE_RESHARDING':
|
|
331
|
-
this.spawn(message.workerId, message.shardId, true);
|
|
395
|
+
this.observe(() => this.spawn(message.workerId, message.shardId, true), `[Worker #${message.workerId}] resharding shard connection failed`);
|
|
332
396
|
break;
|
|
333
397
|
case 'CONNECT_QUEUE':
|
|
334
|
-
this.spawn(message.workerId, message.shardId);
|
|
398
|
+
await this.spawn(message.workerId, message.shardId);
|
|
335
399
|
break;
|
|
336
400
|
case 'CACHE_REQUEST':
|
|
337
401
|
{
|
|
@@ -350,7 +414,7 @@ class WorkerManager extends Map {
|
|
|
350
414
|
catch (error) {
|
|
351
415
|
response = { type: 'CACHE_RESULT', nonce: message.nonce, error: (0, worker_errors_1.serializeWorkerError)(error) };
|
|
352
416
|
}
|
|
353
|
-
this.postMessage(message.workerId, response);
|
|
417
|
+
await this.postMessage(message.workerId, response);
|
|
354
418
|
}
|
|
355
419
|
break;
|
|
356
420
|
case 'RECEIVE_PAYLOAD':
|
|
@@ -395,7 +459,7 @@ class WorkerManager extends Map {
|
|
|
395
459
|
{
|
|
396
460
|
this.get(message.workerId).ready = true;
|
|
397
461
|
if (this.size === this.totalWorkers && [...this.values()].every(w => w.ready)) {
|
|
398
|
-
this.postMessage(this.keys().next().value, {
|
|
462
|
+
await this.postMessage(this.keys().next().value, {
|
|
399
463
|
type: 'BOT_READY',
|
|
400
464
|
});
|
|
401
465
|
this.forEach(w => {
|
|
@@ -409,7 +473,7 @@ class WorkerManager extends Map {
|
|
|
409
473
|
const nextWorker = this.workerQueue.shift();
|
|
410
474
|
if (nextWorker) {
|
|
411
475
|
this.debugger?.info('Spawning next worker');
|
|
412
|
-
nextWorker();
|
|
476
|
+
await nextWorker();
|
|
413
477
|
}
|
|
414
478
|
else {
|
|
415
479
|
this.debugger?.info('No more workers to spawn left');
|
|
@@ -429,7 +493,7 @@ class WorkerManager extends Map {
|
|
|
429
493
|
const response = await this.rest.request(message.method, message.url, message.requestOptions);
|
|
430
494
|
const encodedResponse = response instanceof ArrayBuffer ? Array.from(new Uint8Array(response)) : response;
|
|
431
495
|
const responseType = response instanceof ArrayBuffer ? 'arrayBuffer' : undefined;
|
|
432
|
-
this.postMessage(message.workerId, {
|
|
496
|
+
await this.postMessage(message.workerId, {
|
|
433
497
|
nonce: message.nonce,
|
|
434
498
|
response: encodedResponse,
|
|
435
499
|
responseType,
|
|
@@ -452,18 +516,18 @@ class WorkerManager extends Map {
|
|
|
452
516
|
case 'EVAL_TO_WORKER':
|
|
453
517
|
{
|
|
454
518
|
const nonce = this.generateNonce();
|
|
455
|
-
this.postMessage(message.toWorkerId, {
|
|
519
|
+
const response = await this.sendRequest(nonce, 'Worker evaluation', () => this.postMessage(message.toWorkerId, {
|
|
456
520
|
nonce,
|
|
457
521
|
func: message.func,
|
|
458
522
|
type: 'EXECUTE_EVAL_TO_WORKER',
|
|
459
523
|
toWorkerId: message.toWorkerId,
|
|
460
524
|
vars: message.vars,
|
|
461
|
-
});
|
|
462
|
-
|
|
525
|
+
}));
|
|
526
|
+
await this.postMessage(message.workerId, {
|
|
463
527
|
nonce: message.nonce,
|
|
464
|
-
response
|
|
528
|
+
response,
|
|
465
529
|
type: 'EVAL_RESPONSE',
|
|
466
|
-
})
|
|
530
|
+
});
|
|
467
531
|
}
|
|
468
532
|
break;
|
|
469
533
|
}
|
|
@@ -485,6 +549,21 @@ class WorkerManager extends Map {
|
|
|
485
549
|
this.promises.set(nonce, { resolve: res, timeout });
|
|
486
550
|
});
|
|
487
551
|
}
|
|
552
|
+
async sendRequest(nonce, operation, send) {
|
|
553
|
+
const response = this.generateSendPromise(nonce, operation);
|
|
554
|
+
try {
|
|
555
|
+
const [result] = await Promise.all([response, send()]);
|
|
556
|
+
return result;
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
const pending = this.promises.get(nonce);
|
|
560
|
+
if (pending) {
|
|
561
|
+
this.promises.delete(nonce);
|
|
562
|
+
clearTimeout(pending.timeout);
|
|
563
|
+
}
|
|
564
|
+
throw error;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
488
567
|
async send(data, shardId) {
|
|
489
568
|
const workerId = this.calculateWorkerId(shardId);
|
|
490
569
|
const worker = this.has(workerId);
|
|
@@ -495,13 +574,12 @@ class WorkerManager extends Map {
|
|
|
495
574
|
if (!payload)
|
|
496
575
|
return false;
|
|
497
576
|
const nonce = this.generateNonce();
|
|
498
|
-
this.postMessage(workerId, {
|
|
577
|
+
return this.sendRequest(nonce, 'Shard payload send', () => this.postMessage(workerId, {
|
|
499
578
|
type: 'SEND_PAYLOAD',
|
|
500
579
|
shardId,
|
|
501
580
|
nonce,
|
|
502
581
|
...payload,
|
|
503
|
-
});
|
|
504
|
-
return this.generateSendPromise(nonce, 'Shard payload send');
|
|
582
|
+
}));
|
|
505
583
|
}
|
|
506
584
|
async resolveSendPayload(shardId, payload) {
|
|
507
585
|
const result = await this.options.handleSendPayload?.(shardId, payload);
|
|
@@ -516,8 +594,7 @@ class WorkerManager extends Map {
|
|
|
516
594
|
throw this.createWorkerNotFoundError(workerId);
|
|
517
595
|
}
|
|
518
596
|
const nonce = this.generateNonce();
|
|
519
|
-
this.postMessage(workerId, { shardId, nonce, type: 'SHARD_INFO' });
|
|
520
|
-
return this.generateSendPromise(nonce, 'Shard info request');
|
|
597
|
+
return this.sendRequest(nonce, 'Shard info request', () => this.postMessage(workerId, { shardId, nonce, type: 'SHARD_INFO' }));
|
|
521
598
|
}
|
|
522
599
|
async getWorkerInfo(workerId) {
|
|
523
600
|
const worker = this.has(workerId);
|
|
@@ -525,18 +602,16 @@ class WorkerManager extends Map {
|
|
|
525
602
|
throw this.createWorkerNotFoundError(workerId);
|
|
526
603
|
}
|
|
527
604
|
const nonce = this.generateNonce();
|
|
528
|
-
this.postMessage(workerId, { nonce, type: 'WORKER_INFO' });
|
|
529
|
-
return this.generateSendPromise(nonce, 'Worker info request');
|
|
605
|
+
return this.sendRequest(nonce, 'Worker info request', () => this.postMessage(workerId, { nonce, type: 'WORKER_INFO' }));
|
|
530
606
|
}
|
|
531
|
-
tellWorker(workerId, func, vars) {
|
|
607
|
+
async tellWorker(workerId, func, vars) {
|
|
532
608
|
const nonce = this.generateNonce();
|
|
533
|
-
this.postMessage(workerId, {
|
|
609
|
+
return this.sendRequest(nonce, 'Worker request', () => this.postMessage(workerId, {
|
|
534
610
|
type: 'EXECUTE_EVAL',
|
|
535
611
|
func: func.toString(),
|
|
536
612
|
nonce,
|
|
537
613
|
vars: JSON.stringify(vars),
|
|
538
|
-
});
|
|
539
|
-
return this.generateSendPromise(nonce);
|
|
614
|
+
}));
|
|
540
615
|
}
|
|
541
616
|
tellWorkers(func, vars) {
|
|
542
617
|
const promises = [];
|
|
@@ -583,7 +658,7 @@ class WorkerManager extends Map {
|
|
|
583
658
|
}, this.debugger);
|
|
584
659
|
this.prepareWorkers(spaces);
|
|
585
660
|
// Start workers queue
|
|
586
|
-
this.workerQueue.shift()();
|
|
661
|
+
await this.workerQueue.shift()();
|
|
587
662
|
await this.startResharding();
|
|
588
663
|
}
|
|
589
664
|
async startResharding() {
|
|
@@ -610,7 +685,9 @@ class WorkerManager extends Map {
|
|
|
610
685
|
shardStart: 0,
|
|
611
686
|
}, this.debugger);
|
|
612
687
|
this.prepareWorkers(spaces, true);
|
|
613
|
-
|
|
688
|
+
const firstWorker = this.reshardingWorkerQueue.shift();
|
|
689
|
+
if (firstWorker)
|
|
690
|
+
this.observe(firstWorker, 'Resharding worker spawn failed');
|
|
614
691
|
}, this.options.resharding.interval);
|
|
615
692
|
}
|
|
616
693
|
}
|