diff --git a/src/client/Client.js b/src/client/Client.js index e8fc17ef0538..ce769c2b9506 100644 --- a/src/client/Client.js +++ b/src/client/Client.js @@ -572,6 +572,9 @@ class Client extends BaseClient { if (!Array.isArray(options.partials)) { throw new TypeError('CLIENT_INVALID_OPTION', 'partials', 'an Array'); } + if (typeof options.waitGuildTimeout !== 'number' || isNaN(options.waitGuildTimeout)) { + throw new TypeError('CLIENT_INVALID_OPTION', 'waitGuildTimeout', 'a number'); + } if (typeof options.restWsBridgeTimeout !== 'number' || isNaN(options.restWsBridgeTimeout)) { throw new TypeError('CLIENT_INVALID_OPTION', 'restWsBridgeTimeout', 'a number'); } diff --git a/src/client/websocket/WebSocketShard.js b/src/client/websocket/WebSocketShard.js index 11283345e769..70ace4fce8cb 100644 --- a/src/client/websocket/WebSocketShard.js +++ b/src/client/websocket/WebSocketShard.js @@ -475,12 +475,20 @@ class WebSocketShard extends EventEmitter { return; } const hasGuildsIntent = new Intents(this.manager.client.options.intents).has(Intents.FLAGS.GUILDS); - // Step 2. Create a 15s timeout that will mark the shard as ready if there are still unavailable guilds + // Step 2. Create a timeout that will mark the shard as ready if there are still unavailable guilds + // * The timeout is 15 seconds by default + // * This can be optionally changed in the client options via the `waitGuildTimeout` option + // * a timeout time of zero will skip this timeout, which potentially could cause the Client to miss guilds. + + const { waitGuildTimeout } = this.manager.client.options; + this.readyTimeout = setTimeout( () => { this.debug( `Shard ${hasGuildsIntent ? 'did' : 'will'} not receive any more guild packets` + - `${hasGuildsIntent ? ' in 15 seconds' : ''}.\n Unavailable guild count: ${this.expectedGuilds.size}`, + `${hasGuildsIntent ? ` in ${waitGuildTimeout} ms` : ''}.\nUnavailable guild count: ${ + this.expectedGuilds.size + }`, ); this.readyTimeout = null; @@ -489,7 +497,7 @@ class WebSocketShard extends EventEmitter { this.emit(ShardEvents.ALL_READY, this.expectedGuilds); }, - hasGuildsIntent ? 15_000 : 0, + hasGuildsIntent ? waitGuildTimeout : 0, ).unref(); } diff --git a/src/util/Options.js b/src/util/Options.js index 01690b4cfe4d..2ee1f0910af9 100644 --- a/src/util/Options.js +++ b/src/util/Options.js @@ -70,6 +70,8 @@ * [User Agent](https://discord.com/developers/docs/reference#user-agent) header * @property {PresenceData} [presence={}] Presence data to use upon login * @property {IntentsResolvable} intents Intents to enable for this connection + * @property {number} [waitGuildTimeout=15_000] Time in milliseconds that Clients with the GUILDS intent should wait for + * missing guilds to be recieved before starting the bot. If not specified, the default is 15 seconds. * @property {SweeperOptions} [sweepers={}] Options for cache sweeping * @property {WebsocketOptions} [ws] Options for the WebSocket * @property {HTTPOptions} [http] HTTP options @@ -128,6 +130,7 @@ class Options extends null { */ static createDefault() { return { + waitGuildTimeout: 15_000, shardCount: 1, makeCache: this.cacheWithLimits(this.defaultMakeCacheSettings), messageCacheLifetime: 0, diff --git a/typings/index.d.ts b/typings/index.d.ts index 9fcaaf15b9be..0206ffd7dd7d 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -4004,6 +4004,7 @@ export interface ClientOptions { userAgentSuffix?: string[]; presence?: PresenceData; intents: BitFieldResolvable; + waitGuildTimeout?: number; sweepers?: SweeperOptions; ws?: WebSocketOptions; http?: HTTPOptions;