feat(Sharding): change waitForReady to spawnTimeout (#3080)

This means that you'll not only be able to choose between having a timeout or not, but also to set the amount of milliseconds as you wish.
This commit is contained in:
Antonio Román
2019-04-21 13:34:09 +02:00
committed by SpaceEEC
parent abd9d36816
commit 01c708bc75
4 changed files with 29 additions and 24 deletions

View File

@@ -102,10 +102,11 @@ class Shard extends EventEmitter {
/** /**
* Forks a child process or creates a worker thread for the shard. * Forks a child process or creates a worker thread for the shard.
* <warn>You should not need to call this manually.</warn> * <warn>You should not need to call this manually.</warn>
* @param {boolean} [waitForReady=true] Whether to wait until the {@link Client} has become ready before resolving * @param {number} [spawnTimeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready
* before resolving. (-1 or Infinity for no wait)
* @returns {Promise<ChildProcess>} * @returns {Promise<ChildProcess>}
*/ */
async spawn(waitForReady = true) { async spawn(spawnTimeout = 30000) {
if (this.process) throw new Error('SHARDING_PROCESS_EXISTS', this.id); if (this.process) throw new Error('SHARDING_PROCESS_EXISTS', this.id);
if (this.worker) throw new Error('SHARDING_WORKER_EXISTS', this.id); if (this.worker) throw new Error('SHARDING_WORKER_EXISTS', this.id);
@@ -128,12 +129,12 @@ class Shard extends EventEmitter {
*/ */
this.emit('spawn', this.process || this.worker); this.emit('spawn', this.process || this.worker);
if (!waitForReady) return this.process || this.worker; if (spawnTimeout === -1 || spawnTimeout === Infinity) return this.process || this.worker;
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
this.once('ready', resolve); this.once('ready', resolve);
this.once('disconnect', () => reject(new Error('SHARDING_READY_DISCONNECTED', this.id))); this.once('disconnect', () => reject(new Error('SHARDING_READY_DISCONNECTED', this.id)));
this.once('death', () => reject(new Error('SHARDING_READY_DIED', this.id))); this.once('death', () => reject(new Error('SHARDING_READY_DIED', this.id)));
setTimeout(() => reject(new Error('SHARDING_READY_TIMEOUT', this.id)), 30000); setTimeout(() => reject(new Error('SHARDING_READY_TIMEOUT', this.id)), spawnTimeout);
}); });
return this.process || this.worker; return this.process || this.worker;
} }
@@ -156,13 +157,14 @@ class Shard extends EventEmitter {
/** /**
* Kills and restarts the shard's process/worker. * Kills and restarts the shard's process/worker.
* @param {number} [delay=500] How long to wait between killing the process/worker and restarting it (in milliseconds) * @param {number} [delay=500] How long to wait between killing the process/worker and restarting it (in milliseconds)
* @param {boolean} [waitForReady=true] Whether to wait until the {@link Client} has become ready before resolving * @param {number} [spawnTimeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready
* before resolving. (-1 or Infinity for no wait)
* @returns {Promise<ChildProcess>} * @returns {Promise<ChildProcess>}
*/ */
async respawn(delay = 500, waitForReady = true) { async respawn(delay = 500, spawnTimeout) {
this.kill(); this.kill();
if (delay > 0) await Util.delayFor(delay); if (delay > 0) await Util.delayFor(delay);
return this.spawn(waitForReady); return this.spawn(spawnTimeout);
} }
/** /**
@@ -308,8 +310,8 @@ class Shard extends EventEmitter {
// Shard is requesting a respawn of all shards // Shard is requesting a respawn of all shards
if (message._sRespawnAll) { if (message._sRespawnAll) {
const { shardDelay, respawnDelay, waitForReady } = message._sRespawnAll; const { shardDelay, respawnDelay, spawnTimeout } = message._sRespawnAll;
this.manager.respawnAll(shardDelay, respawnDelay, waitForReady).catch(() => { this.manager.respawnAll(shardDelay, respawnDelay, spawnTimeout).catch(() => {
// Do nothing // Do nothing
}); });
return; return;

View File

@@ -143,12 +143,13 @@ class ShardClientUtil {
* @param {number} [shardDelay=5000] How long to wait between shards (in milliseconds) * @param {number} [shardDelay=5000] How long to wait between shards (in milliseconds)
* @param {number} [respawnDelay=500] How long to wait between killing a shard's process/worker and restarting it * @param {number} [respawnDelay=500] How long to wait between killing a shard's process/worker and restarting it
* (in milliseconds) * (in milliseconds)
* @param {boolean} [waitForReady=true] Whether to wait for a shard to become ready before continuing to another * @param {number} [spawnTimeout=30000] The amount in milliseconds to wait for a shard to become ready before
* continuing to another. (-1 or Infinity for no wait)
* @returns {Promise<void>} Resolves upon the message being sent * @returns {Promise<void>} Resolves upon the message being sent
* @see {@link ShardingManager#respawnAll} * @see {@link ShardingManager#respawnAll}
*/ */
respawnAll(shardDelay = 5000, respawnDelay = 500, waitForReady = true) { respawnAll(shardDelay = 5000, respawnDelay = 500, spawnTimeout = 30000) {
return this.send({ _sRespawnAll: { shardDelay, respawnDelay, waitForReady } }); return this.send({ _sRespawnAll: { shardDelay, respawnDelay, spawnTimeout } });
} }
/** /**

View File

@@ -156,12 +156,13 @@ class ShardingManager extends EventEmitter {
/** /**
* Spawns multiple shards. * Spawns multiple shards.
* @param {number} [amount=this.totalShards] Number of shards to spawn * @param {number|string} [amount=this.totalShards] Number of shards to spawn
* @param {number} [delay=5500] How long to wait in between spawning each shard (in milliseconds) * @param {number} [delay=5500] How long to wait in between spawning each shard (in milliseconds)
* @param {boolean} [waitForReady=true] Whether to wait for a shard to become ready before continuing to another * @param {number} [spawnTimeout=30000] The amount in milliseconds to wait until the {@link Client} has become ready
* before resolving. (-1 or Infinity for no wait)
* @returns {Promise<Collection<number, Shard>>} * @returns {Promise<Collection<number, Shard>>}
*/ */
async spawn(amount = this.totalShards, delay = 5500, waitForReady = true) { async spawn(amount = this.totalShards, delay = 5500, spawnTimeout) {
// Obtain/verify the number of shards to spawn // Obtain/verify the number of shards to spawn
if (amount === 'auto') { if (amount === 'auto') {
amount = await Util.fetchRecommendedShards(this.token); amount = await Util.fetchRecommendedShards(this.token);
@@ -193,7 +194,7 @@ class ShardingManager extends EventEmitter {
for (const shardID of this.shardList) { for (const shardID of this.shardList) {
const promises = []; const promises = [];
const shard = this.createShard(shardID); const shard = this.createShard(shardID);
promises.push(shard.spawn(waitForReady)); promises.push(shard.spawn(spawnTimeout));
if (delay > 0 && this.shards.size !== this.shardList.length) promises.push(Util.delayFor(delay)); if (delay > 0 && this.shards.size !== this.shardList.length) promises.push(Util.delayFor(delay));
await Promise.all(promises); // eslint-disable-line no-await-in-loop await Promise.all(promises); // eslint-disable-line no-await-in-loop
} }
@@ -245,13 +246,14 @@ class ShardingManager extends EventEmitter {
* @param {number} [shardDelay=5000] How long to wait between shards (in milliseconds) * @param {number} [shardDelay=5000] How long to wait between shards (in milliseconds)
* @param {number} [respawnDelay=500] How long to wait between killing a shard's process and restarting it * @param {number} [respawnDelay=500] How long to wait between killing a shard's process and restarting it
* (in milliseconds) * (in milliseconds)
* @param {boolean} [waitForReady=true] Whether to wait for a shard to become ready before continuing to another * @param {number} [spawnTimeout=30000] The amount in milliseconds to wait for a shard to become ready before
* continuing to another. (-1 or Infinity for no wait)
* @returns {Promise<Collection<string, Shard>>} * @returns {Promise<Collection<string, Shard>>}
*/ */
async respawnAll(shardDelay = 5000, respawnDelay = 500, waitForReady = true) { async respawnAll(shardDelay = 5000, respawnDelay = 500, spawnTimeout) {
let s = 0; let s = 0;
for (const shard of this.shards.values()) { for (const shard of this.shards.values()) {
const promises = [shard.respawn(respawnDelay, waitForReady)]; const promises = [shard.respawn(respawnDelay, spawnTimeout)];
if (++s < this.shards.size && shardDelay > 0) promises.push(Util.delayFor(shardDelay)); if (++s < this.shards.size && shardDelay > 0) promises.push(Util.delayFor(shardDelay));
await Promise.all(promises); // eslint-disable-line no-await-in-loop await Promise.all(promises); // eslint-disable-line no-await-in-loop
} }

10
typings/index.d.ts vendored
View File

@@ -921,9 +921,9 @@ declare module 'discord.js' {
public eval<T>(fn: (client: Client) => T): Promise<T[]>; public eval<T>(fn: (client: Client) => T): Promise<T[]>;
public fetchClientValue(prop: string): Promise<any>; public fetchClientValue(prop: string): Promise<any>;
public kill(): void; public kill(): void;
public respawn(delay?: number, waitForReady?: boolean): Promise<ChildProcess>; public respawn(delay?: number, spawnTimeout?: number): Promise<ChildProcess>;
public send(message: any): Promise<Shard>; public send(message: any): Promise<Shard>;
public spawn(waitForReady?: boolean): Promise<ChildProcess>; public spawn(spawnTimeout?: number): Promise<ChildProcess>;
public on(event: 'death', listener: (child: ChildProcess) => void): this; public on(event: 'death', listener: (child: ChildProcess) => void): this;
public on(event: 'disconnect' | 'ready' | 'reconnecting', listener: () => void): this; public on(event: 'disconnect' | 'ready' | 'reconnecting', listener: () => void): this;
@@ -953,7 +953,7 @@ declare module 'discord.js' {
public broadcastEval(script: string): Promise<any[]>; public broadcastEval(script: string): Promise<any[]>;
public broadcastEval<T>(fn: (client: Client) => T): Promise<T[]>; public broadcastEval<T>(fn: (client: Client) => T): Promise<T[]>;
public fetchClientValues(prop: string): Promise<any[]>; public fetchClientValues(prop: string): Promise<any[]>;
public respawnAll(shardDelay?: number, respawnDelay?: number, waitForReady?: boolean): Promise<void>; public respawnAll(shardDelay?: number, respawnDelay?: number, spawnTimeout?: number): Promise<void>;
public send(message: any): Promise<void>; public send(message: any): Promise<void>;
public static singleton(client: Client, mode: ShardingManagerMode): ShardClientUtil; public static singleton(client: Client, mode: ShardingManagerMode): ShardClientUtil;
@@ -979,8 +979,8 @@ declare module 'discord.js' {
public broadcastEval(script: string): Promise<any[]>; public broadcastEval(script: string): Promise<any[]>;
public createShard(id: number): Shard; public createShard(id: number): Shard;
public fetchClientValues(prop: string): Promise<any[]>; public fetchClientValues(prop: string): Promise<any[]>;
public respawnAll(shardDelay?: number, respawnDelay?: number, waitForReady?: boolean): Promise<Collection<number, Shard>>; public respawnAll(shardDelay?: number, respawnDelay?: number, spawnTimeout?: number): Promise<Collection<number, Shard>>;
public spawn(amount?: number | 'auto', delay?: number, waitForReady?: boolean): Promise<Collection<number, Shard>>; public spawn(amount?: number | 'auto', delay?: number, spawnTimeout?: number): Promise<Collection<number, Shard>>;
public on(event: 'shardCreate', listener: (shard: Shard) => void): this; public on(event: 'shardCreate', listener: (shard: Shard) => void): this;