TerrorByte
TerrorByte
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
Alright, thank you very much. I'll figure out a way to only remove events created by me and not the client. Much appreciated!
12 replies
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
Awesome, good to know. I'm assuming this method should be considered unsafe then and not used? At least, not during startup
12 replies
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
Hmm, oddly enough I don't, even after enabling all my bot's features again. Thinking through it, is that call removing the ready event from the client, therefore preventing it from being fired upon initial construction?
12 replies
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
Let me give that a shot, I'll report back in a sec
12 replies
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
TL;DR 1) Sharding manager spawns a shard 2) The shard creates a client of type CrystalClient, which extends Client 3) The CrystalClient constructor calls the loadEvents method, which A) iterates over all files and filters the files by .js extensions and B) attaches them to the client object using client[event.once ? "once" : "on"](event.name, execute), where event.once and execute is a property on the imported Event and execute is defined as
const execute = (...args: any[]): void => {
void event.execute(...args)
}
const execute = (...args: any[]): void => {
void event.execute(...args)
}
The whole event loading process is completed after approx. 55.416ms according to the last run of my bot 4) One of those events that is loaded is the client's ready event, which fires fine 5) However, after about 30 seconds the bot times out anyway 6) If void loadEvents() is replaced with this.on("ready", () => { console.log("ready") }) within the constructor of CrystalClient, no errors occur, leading me to believe it's something to do with the file loading process. However, again, the ready event is still being thrown as indicated by hardcoded console.log() methods within the ready event file itself
12 replies
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
npm list discord.js && node -v:
[email protected] V:\Development Projects\crystal-bot
└── [email protected] -> .\node_modules\.pnpm\[email protected]\node_modules\discord.js
v20.9.0
[email protected] V:\Development Projects\crystal-bot
└── [email protected] -> .\node_modules\.pnpm\[email protected]\node_modules\discord.js
v20.9.0
I know there's a lot there, I can break it down if needed but basically, ready event is being fired, but shard is still timing out and idk why
12 replies
DIAdiscord.js - Imagine an app
Created by TerrorByte on 11/25/2023 in #djs-questions
Receiving "ShardingReadyTimeout" even though ready event is firing
I reached a character limit, so here's the rest of the info: Here is my eventHandler class, which contains the loadEvents method:
import { type RestEvents } from "discord.js"
import { loadFiles } from "./fileLoader"
import { type Event } from "../../types/Event"
import CrystalClient from "../../types/CrystalClient"

export async function loadEvents(client: CrystalClient): Promise<void> {
console.time("Events loaded")

const events = []
CrystalClient.events.clear()
client.removeAllListeners()

const files = await loadFiles("modules/events")

for (const file of files) {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const event: Event = require(file)
if (event.name == null) throw new Error("Invalid event file")

const execute = (...args: any[]): void => {
void event.execute(...args)
}

event.rest
? client.rest[event.once ? "once" : "on"](event.name as keyof RestEvents, execute)
: client[event.once ? "once" : "on"](event.name, execute)

CrystalClient.events.set(event.name, execute)
events.push({ Event: event.name, Status: "✅" })
} catch (error) {
console.error(error)
events.push({ Event: file.replace(/\\/g, "/").split("/").pop()?.slice(0, -3), Status: "🛑" })
}
}

console.table(events, ["Event", "Status"])
console.info("\n\x1b[36m%s\x1b[0m", "Loaded Events")
console.timeEnd("Events loaded")
}
import { type RestEvents } from "discord.js"
import { loadFiles } from "./fileLoader"
import { type Event } from "../../types/Event"
import CrystalClient from "../../types/CrystalClient"

export async function loadEvents(client: CrystalClient): Promise<void> {
console.time("Events loaded")

const events = []
CrystalClient.events.clear()
client.removeAllListeners()

const files = await loadFiles("modules/events")

for (const file of files) {
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const event: Event = require(file)
if (event.name == null) throw new Error("Invalid event file")

const execute = (...args: any[]): void => {
void event.execute(...args)
}

event.rest
? client.rest[event.once ? "once" : "on"](event.name as keyof RestEvents, execute)
: client[event.once ? "once" : "on"](event.name, execute)

CrystalClient.events.set(event.name, execute)
events.push({ Event: event.name, Status: "✅" })
} catch (error) {
console.error(error)
events.push({ Event: file.replace(/\\/g, "/").split("/").pop()?.slice(0, -3), Status: "🛑" })
}
}

console.table(events, ["Event", "Status"])
console.info("\n\x1b[36m%s\x1b[0m", "Loaded Events")
console.timeEnd("Events loaded")
}
The loadFiles() function is defined as
import { glob } from "glob"
import path from "node:path"

async function deleteCachedFile(file: string): Promise<void> {
const filePath = path.resolve(file)
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
if (require.cache[filePath] != null) delete require.cache[filePath]
}

export async function loadFiles(dirName: string): Promise<string[]> {
try {
const files = await glob(path.join(process.cwd(), dirName, "**/*.js").replace(/\\/g, "/"))
const jsFiles = files.filter(file => path.extname(file) === ".js")
await Promise.all(jsFiles.map(deleteCachedFile))
return jsFiles
} catch (error: any) {
console.error(`Error loading files from directory ${dirName}: ${error}`)
throw error
}
}
import { glob } from "glob"
import path from "node:path"

async function deleteCachedFile(file: string): Promise<void> {
const filePath = path.resolve(file)
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
if (require.cache[filePath] != null) delete require.cache[filePath]
}

export async function loadFiles(dirName: string): Promise<string[]> {
try {
const files = await glob(path.join(process.cwd(), dirName, "**/*.js").replace(/\\/g, "/"))
const jsFiles = files.filter(file => path.extname(file) === ".js")
await Promise.all(jsFiles.map(deleteCachedFile))
return jsFiles
} catch (error: any) {
console.error(`Error loading files from directory ${dirName}: ${error}`)
throw error
}
}
If I change the void loadEvents(CrystalClient.client) line to a standard this.on("ready", () => { console.log("ready") }) method, it works. But when I'm loading events dynamically from an event file, it freaks out. For reference, this event is being registered fine
import { type Event } from "../../types/Event"
import { loadCommands } from "../utils/commandHandler"
import { getChannels } from "../utils/channelRegistrar"
import type CrystalClient from "../../types/CrystalClient"

module.exports = {
name: "ready",
once: false,
rest: false,
execute: async function (client: CrystalClient): Promise<void> {
// void loadCommands(client)
// void getChannels(client)

console.log(`Logged in as ${client.user?.tag}`)
},
} satisfies Event
import { type Event } from "../../types/Event"
import { loadCommands } from "../utils/commandHandler"
import { getChannels } from "../utils/channelRegistrar"
import type CrystalClient from "../../types/CrystalClient"

module.exports = {
name: "ready",
once: false,
rest: false,
execute: async function (client: CrystalClient): Promise<void> {
// void loadCommands(client)
// void getChannels(client)

console.log(`Logged in as ${client.user?.tag}`)
},
} satisfies Event
But the error still fires
Launched shard 0
┌─────────┬─────────┬────────┐
│ (index) │ Event │ Status │
├─────────┼─────────┼────────┤
│ 0 │ 'ready' │ '✅' │
└─────────┴─────────┴────────┘

Loaded Events
Events loaded: 55.416ms
Logged in as <BOT ID HERE> // This is fired from the ready event
//////// After about 30 seconds
Error [ShardingReadyTimeout]: Shard 0's Client took too long to become ready.
at Timeout.onTimeout (V:\Development Projects\crystal-bot\node_modules\.pnpm\[email protected]\node_modules\discord.js\src\sharding\Shard.js:183:16)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7) error
Launched shard 0
┌─────────┬─────────┬────────┐
│ (index) │ Event │ Status │
├─────────┼─────────┼────────┤
│ 0 │ 'ready' │ '✅' │
└─────────┴─────────┴────────┘

Loaded Events
Events loaded: 55.416ms
Logged in as <BOT ID HERE> // This is fired from the ready event
//////// After about 30 seconds
Error [ShardingReadyTimeout]: Shard 0's Client took too long to become ready.
at Timeout.onTimeout (V:\Development Projects\crystal-bot\node_modules\.pnpm\[email protected]\node_modules\discord.js\src\sharding\Shard.js:183:16)
at listOnTimeout (node:internal/timers:573:17)
at process.processTimers (node:internal/timers:514:7) error
12 replies