example(bigbot): Spawn one shard at a time (#4127)

* Spawn one shard at a time

* remove useless code in ShardIdentified handling

* update comment on tellWorkerToIdentify

* fix mistake

* Use request identify

This also makes some unrelated changes needed to make the example
comple when using the build from this branch.

* remove debug logs
This commit is contained in:
Fleny
2025-05-25 14:00:47 +05:30
committed by GitHub
parent dff9df5a59
commit 5cb7c1d1d2
6 changed files with 39 additions and 13 deletions
+1 -3
View File
@@ -1,4 +1,4 @@
import { Collection, LogDepth, createBot, type logger } from '@discordeno/bot' import { Collection, createBot } from '@discordeno/bot'
import { DISCORD_TOKEN, GATEWAY_AUTHORIZATION, GATEWAY_INTENTS, GATEWAY_URL, REST_AUTHORIZATION, REST_URL } from '../config.js' import { DISCORD_TOKEN, GATEWAY_AUTHORIZATION, GATEWAY_INTENTS, GATEWAY_URL, REST_AUTHORIZATION, REST_URL } from '../config.js'
import type { ManagerGetShardInfoFromGuildId, ShardInfo, WorkerPresencesUpdate, WorkerShardPayload } from '../gateway/worker/types.js' import type { ManagerGetShardInfoFromGuildId, ShardInfo, WorkerPresencesUpdate, WorkerShardPayload } from '../gateway/worker/types.js'
import type { Command } from './commands.js' import type { Command } from './commands.js'
@@ -33,8 +33,6 @@ const rawBot = createBot({
export const bot = rawBot as CustomBot export const bot = rawBot as CustomBot
// TEMPLATE-SETUP: If you want/need to add any custom properties on the Bot type, you can do it in these lines below and the `CustomBot` type below. Make sure to do it in both or else you will get an error by TypeScript // TEMPLATE-SETUP: If you want/need to add any custom properties on the Bot type, you can do it in these lines below and the `CustomBot` type below. Make sure to do it in both or else you will get an error by TypeScript
// We need to set the log depth for the default discordeno logger or else only the first param will be logged
;(bot.logger as typeof logger).setDepth(LogDepth.Full)
bot.commands = new Collection() bot.commands = new Collection()
+17 -3
View File
@@ -1,12 +1,12 @@
import type { Worker } from 'node:worker_threads' import type { Worker } from 'node:worker_threads'
import { LogDepth, createGatewayManager, createLogger, createRestManager } from '@discordeno/bot' import { createGatewayManager, createLogger, createRestManager } from '@discordeno/bot'
import { DISCORD_TOKEN, GATEWAY_INTENTS, REST_AUTHORIZATION, REST_URL, SHARDS_PER_WORKER, TOTAL_SHARDS, TOTAL_WORKERS } from '../config.js' import { DISCORD_TOKEN, GATEWAY_INTENTS, REST_AUTHORIZATION, REST_URL, SHARDS_PER_WORKER, TOTAL_SHARDS, TOTAL_WORKERS } from '../config.js'
import { promiseWithResolvers } from '../util.js'
import { createWorker } from './worker/createWorker.js' import { createWorker } from './worker/createWorker.js'
import type { WorkerMessage } from './worker/types.js' import type { ManagerMessage, WorkerMessage } from './worker/types.js'
export const workers = new Map<number, Worker>() export const workers = new Map<number, Worker>()
export const logger = createLogger({ name: 'GATEWAY' }) export const logger = createLogger({ name: 'GATEWAY' })
logger.setDepth(LogDepth.Full)
const restManager = createRestManager({ const restManager = createRestManager({
token: DISCORD_TOKEN, token: DISCORD_TOKEN,
@@ -37,6 +37,20 @@ gatewayManager.tellWorkerToIdentify = async (workerId, shardId, bucketId) => {
type: 'IdentifyShard', type: 'IdentifyShard',
shardId, shardId,
} satisfies WorkerMessage) } satisfies WorkerMessage)
const { promise, resolve } = promiseWithResolvers<void>()
const waitForShardIdentified = (message: ManagerMessage) => {
if (message.type === 'ShardIdentified' && message.shardId === shardId) {
resolve()
}
}
worker.on('message', waitForShardIdentified)
await promise
worker.off('message', waitForShardIdentified)
} }
gatewayManager.sendPayload = async (shardId, payload) => { gatewayManager.sendPayload = async (shardId, payload) => {
@@ -62,6 +62,10 @@ export function createWorker(workerId: number): Worker {
shardInfoRequests.delete(message.nonce) shardInfoRequests.delete(message.nonce)
return return
} }
if (message.type === 'ShardIdentified') {
logger.info(`Shard #${message.shardId} identified`)
return
}
logger.warn(`Worker - Received unknown message type: ${(message as { type: string }).type}`) logger.warn(`Worker - Received unknown message type: ${(message as { type: string }).type}`)
}) })
+8 -3
View File
@@ -1,6 +1,6 @@
import type { ShardSocketRequest, StatusUpdate } from '@discordeno/bot' import type { DiscordUpdatePresence, ShardSocketRequest } from '@discordeno/bot'
export type ManagerMessage = ManagerRequestIdentify | ManagerShardInfo export type ManagerMessage = ManagerRequestIdentify | ManagerShardIdentified | ManagerShardInfo
export type WorkerMessage = WorkerIdentifyShard | WorkerAllowIdentify | WorkerShardPayload | WorkerPresencesUpdate | WorkerShardInfo export type WorkerMessage = WorkerIdentifyShard | WorkerAllowIdentify | WorkerShardPayload | WorkerPresencesUpdate | WorkerShardInfo
export interface WorkerIdentifyShard { export interface WorkerIdentifyShard {
@@ -26,7 +26,7 @@ export interface WorkerShardPayload {
export interface WorkerPresencesUpdate { export interface WorkerPresencesUpdate {
type: 'EditShardsPresence' type: 'EditShardsPresence'
payload: StatusUpdate payload: DiscordUpdatePresence
} }
export interface WorkerShardInfo { export interface WorkerShardInfo {
@@ -71,3 +71,8 @@ export interface ManagerGetShardInfoFromGuildId {
type: 'ShardInfoFromGuild' type: 'ShardInfoFromGuild'
guildId: string | undefined guildId: string | undefined
} }
export interface ManagerShardIdentified {
type: 'ShardIdentified'
shardId: number
}
+8 -2
View File
@@ -1,7 +1,7 @@
import assert from 'node:assert' import assert from 'node:assert'
import { createHash } from 'node:crypto' import { createHash } from 'node:crypto'
import { workerData as _workerData, parentPort } from 'node:worker_threads' import { workerData as _workerData, parentPort } from 'node:worker_threads'
import { DiscordenoShard, GatewayOpcodes, LogDepth, createLogger } from '@discordeno/bot' import { DiscordenoShard, GatewayOpcodes, createLogger } from '@discordeno/bot'
import { type Channel as amqpChannel, connect as connectAmqp } from 'amqplib' import { type Channel as amqpChannel, connect as connectAmqp } from 'amqplib'
import { promiseWithResolvers } from '../../util.js' import { promiseWithResolvers } from '../../util.js'
import type { ManagerMessage, WorkerCreateData, WorkerMessage } from './types.js' import type { ManagerMessage, WorkerCreateData, WorkerMessage } from './types.js'
@@ -11,7 +11,6 @@ assert(parentPort)
const workerData: WorkerCreateData = _workerData const workerData: WorkerCreateData = _workerData
const logger = createLogger({ name: `Worker #${workerData.workerId}` }) const logger = createLogger({ name: `Worker #${workerData.workerId}` })
logger.setDepth(LogDepth.Full)
const identifyPromises = new Map<number, () => void>() const identifyPromises = new Map<number, () => void>()
const shards = new Map<number, DiscordenoShard>() const shards = new Map<number, DiscordenoShard>()
@@ -23,6 +22,8 @@ if (workerData.messageQueue.enabled) {
} }
parentPort.on('message', async (message: WorkerMessage) => { parentPort.on('message', async (message: WorkerMessage) => {
assert(parentPort)
if (message.type === 'IdentifyShard') { if (message.type === 'IdentifyShard') {
logger.info(`Starting to identify shard #${message.shardId}`) logger.info(`Starting to identify shard #${message.shardId}`)
const shard = shards.get(message.shardId) ?? createShard(message.shardId) const shard = shards.get(message.shardId) ?? createShard(message.shardId)
@@ -30,6 +31,11 @@ parentPort.on('message', async (message: WorkerMessage) => {
await shard.identify() await shard.identify()
parentPort.postMessage({
type: 'ShardIdentified',
shardId: message.shardId,
} satisfies ManagerMessage)
return return
} }
if (message.type === 'AllowIdentify') { if (message.type === 'AllowIdentify') {
+1 -2
View File
@@ -1,4 +1,4 @@
import { LogDepth, createLogger, createRestManager } from '@discordeno/bot' import { createLogger, createRestManager } from '@discordeno/bot'
import { DISCORD_TOKEN } from '../config.js' import { DISCORD_TOKEN } from '../config.js'
import { setupRestAnalyticsHooks } from './influx.js' import { setupRestAnalyticsHooks } from './influx.js'
@@ -7,7 +7,6 @@ const manager = createRestManager({
}) })
export const logger = createLogger({ name: 'REST' }) export const logger = createLogger({ name: 'REST' })
logger.setDepth(LogDepth.Full)
setupRestAnalyticsHooks(manager, logger) setupRestAnalyticsHooks(manager, logger)