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 10:30:47 +02:00
committed by GitHub
parent dff9df5a59
commit 5cb7c1d1d2
6 changed files with 39 additions and 13 deletions

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 type { ManagerGetShardInfoFromGuildId, ShardInfo, WorkerPresencesUpdate, WorkerShardPayload } from '../gateway/worker/types.js'
import type { Command } from './commands.js'
@@ -33,8 +33,6 @@ const rawBot = createBot({
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
// 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()

View File

@@ -1,12 +1,12 @@
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 { promiseWithResolvers } from '../util.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 logger = createLogger({ name: 'GATEWAY' })
logger.setDepth(LogDepth.Full)
const restManager = createRestManager({
token: DISCORD_TOKEN,
@@ -37,6 +37,20 @@ gatewayManager.tellWorkerToIdentify = async (workerId, shardId, bucketId) => {
type: 'IdentifyShard',
shardId,
} 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) => {

View File

@@ -62,6 +62,10 @@ export function createWorker(workerId: number): Worker {
shardInfoRequests.delete(message.nonce)
return
}
if (message.type === 'ShardIdentified') {
logger.info(`Shard #${message.shardId} identified`)
return
}
logger.warn(`Worker - Received unknown message type: ${(message as { type: string }).type}`)
})

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 interface WorkerIdentifyShard {
@@ -26,7 +26,7 @@ export interface WorkerShardPayload {
export interface WorkerPresencesUpdate {
type: 'EditShardsPresence'
payload: StatusUpdate
payload: DiscordUpdatePresence
}
export interface WorkerShardInfo {
@@ -71,3 +71,8 @@ export interface ManagerGetShardInfoFromGuildId {
type: 'ShardInfoFromGuild'
guildId: string | undefined
}
export interface ManagerShardIdentified {
type: 'ShardIdentified'
shardId: number
}

View File

@@ -1,7 +1,7 @@
import assert from 'node:assert'
import { createHash } from 'node:crypto'
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 { promiseWithResolvers } from '../../util.js'
import type { ManagerMessage, WorkerCreateData, WorkerMessage } from './types.js'
@@ -11,7 +11,6 @@ assert(parentPort)
const workerData: WorkerCreateData = _workerData
const logger = createLogger({ name: `Worker #${workerData.workerId}` })
logger.setDepth(LogDepth.Full)
const identifyPromises = new Map<number, () => void>()
const shards = new Map<number, DiscordenoShard>()
@@ -23,6 +22,8 @@ if (workerData.messageQueue.enabled) {
}
parentPort.on('message', async (message: WorkerMessage) => {
assert(parentPort)
if (message.type === 'IdentifyShard') {
logger.info(`Starting to identify shard #${message.shardId}`)
const shard = shards.get(message.shardId) ?? createShard(message.shardId)
@@ -30,6 +31,11 @@ parentPort.on('message', async (message: WorkerMessage) => {
await shard.identify()
parentPort.postMessage({
type: 'ShardIdentified',
shardId: message.shardId,
} satisfies ManagerMessage)
return
}
if (message.type === 'AllowIdentify') {

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 { setupRestAnalyticsHooks } from './influx.js'
@@ -7,7 +7,6 @@ const manager = createRestManager({
})
export const logger = createLogger({ name: 'REST' })
logger.setDepth(LogDepth.Full)
setupRestAnalyticsHooks(manager, logger)