-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for sharding out of the box. #911
Comments
Hi! Can you provide minimal reproduction repository? NestJS and discord.js are not directly related in any way. How would you like to see sharding out of the box? |
Yeah I understand that NestJS and discord aren't directly related. To be honest, I'd prefer something like this... |- src
main.ts
app.module.ts
bot
- bot.module.ts
- bot.gateway.ts then in const manager = new ShardManager(path.join(__dirname, 'bot', 'bot.module.ts'), { token: configService.get<string>('discord.bot.token')});
manager.spawn(); |
/* spawn-shards.ts */
async function createShardingManager() {
const appContext = await NestFactory.createApplicationContext(ConfigModule);
const configService = appContext.get(ConfigService);
const manager = new ShardManager(/* path to main.ts/js */, { token: configService.get<string>('discord.bot.token')});
appContext.close();
return manager;
}
createShardingManager().then((manager) => {
manager.spawn();
}); |
For anyone coming across this, I have found a solution using @fjodor-rybakov help, follow the steps below. Hopefully the documentation will be updated to include this. In your
You may also need to add a const Path = require('path');
module.exports = function (options) {
return {
...options,
entry: {
server: options.entry,
bot: Path.join(__dirname, 'src', 'bot.ts')
},
output: {
filename: '[name].js'
}
};
}; Secondly, change your Steps:
shared.module.ts (example)import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import appConfig from './config/app.config';
import discordConfig from './config/discord.config';
@Module({
imports: [
ConfigModule.forRoot({
cache: true,
isGlobal: true,
load: [
appConfig,
discordConfig,
]
}),
],
})
export class SharedModule {} app.module.ts (example)import { Module } from '@nestjs/common';
import { SharedModule } from "./shared.module";
@Module({
imports: [
SharedModule
],
})
export class AppModule {} main.ts (example)import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config';
export async function bootstrap() {
const app = await NestFactory.create(AppModule, { cors: true });
const config = app.get(ConfigService);
if (config.get<boolean>('app.debug')) {
app.getHttpAdapter().getInstance().set('json spaces', 2);
}
const port = config.get<string>('app.port');
await app.listen(port);
} bot.ts (required)import { NestFactory } from '@nestjs/core';
import { BotModule } from "./bot/bot.module";
async function bootstrap() {
const app = await NestFactory.createApplicationContext(BotModule);
}
bootstrap(); server.ts (required)import { NestFactory } from "@nestjs/core";
import { ConfigService } from "@nestjs/config";
import * as Path from "path";
import { ShardingManager } from 'discord.js';
import { SharedModule } from "./shared.module";
import { bootstrap } from './main';
async function createShardingManager() {
const appContext = await NestFactory.createApplicationContext(SharedModule);
const config = appContext.get(ConfigService);
const manager = new ShardingManager(Path.join(__dirname, 'bot.js'), {
token: config.get<string>('discord.bot.token')
});
return manager;
}
bootstrap().then(() => createShardingManager()).then((manager) => {
manager.spawn();
manager.on("shardCreate", shard => {
shard.on('reconnecting', () => {
console.log(`Reconnecting shard: [${shard.id}]`);
});
shard.on('spawn', () => {
console.log(`Spawned shard: [${shard.id}]`);
});
shard.on('ready', () => {
console.log(` Shard [${shard.id}] is ready`);
});
shard.on('death', () => {
console.log(`Died shard: [${shard.id}]`);
});
shard.on('error', (err)=>{
console.log(`Error in [${shard.id}] with : ${err} `)
shard.respawn()
})
});
}); bot.module.ts (required)import { Module } from '@nestjs/common';
import { DiscordModule } from '@discord-nestjs/core';
import { BotGateway } from './bot.gateway'
import { GatewayIntentBits } from "discord.js";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { SharedModule } from "../shared.module";
@Module({
imports: [
SharedModule,
DiscordModule.forRootAsync({
imports: [ConfigModule],
useFactory: (config: ConfigService) => ({
token: config.get<string>('discord.bot.token'),
discordClientOptions: {
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMembers,
GatewayIntentBits.GuildWebhooks,
GatewayIntentBits.GuildInvites,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.DirectMessages,
GatewayIntentBits.MessageContent
],
},
}),
inject: [ConfigService],
}),
DiscordModule.forFeature()
],
providers: [BotGateway]
})
export class BotModule {} My directory structure looks something as shown below. My advice would be to keep all your bot related code within the
Note, if you're using the |
@KieronWiltshire Thank you for your comment, however I'm wondering if there is anything to prevent each shard from registering the commands. My understanding is that by default the library will register all commands as application commands, and if there are multiple shards each of them is going to try to perform that registration |
@DJDavid98 not sure I understand your issue |
The library register the commands by default, as per the docs:
So each time a shard starts up, it will register the global commands, that is my understanding at least. My existing bot did not use this and there all I did was only let shard 0 update the commands, but I'm not sure such filtering is possible here. |
I'm still not sure I understand your problem. Link me to the docs in question please. |
Here are the docs: https://github.com/fjodor-rybakov/discord-nestjs/tree/master/packages/core#%E2%84%B9%EF%B8%8F-automatic-registration-of-slash-commands- Without sharding, the As soon as you introduce sharding, the |
@DJDavid98 why does that bother you? in theory thats how it works... thats how it's suggested in the Discordjs docs or at least implied anyway... https://discordjs.guide/sharding/#when-to-shard What is the exact problem you're having? |
Command registration needs to happen only once during application startup. By running the command registration multiple times there is a possibility for race conditions as multiple processes simultaneously start registering commands, and in case the |
I see, but other than it being "wasteful" it works as intended right? |
Technically speaking, for my essentially "hello world" bot at this stage, yes, it currently does. However for a larger bot with multiple commands where registering them might take longer, I feel like this can cause issues later down the line. I specifically wanted to ask if there is some way you are aware of to prevent this. I tried to look into using |
To be fair, I've never created a full featured discord bot. I've always just loved poking around at things, the intentions are there to build a bot at some point, but not in my immediate scope for the project I work on. So for full transparency, I have no idea if sharding in this manner actually works at scale. I personally just struggled to get this working, and I thought if I ever was going to make a bot using NestJS, I'd want to make sure it can absolutely be done. So I went out and did some research on this and came back with the method above, but again other than getting it to just "work," I have no idea. Now with all that being said, if you'd want to try something else instead of discord-nestjs, I would highly recommend Necord. I wrote up the sharding part into the docs on there and the main dev is extremely active in taking feature requests etc... so if this is still an issue over on the necord package, bring it up to the dev on the necord discord. He will gladly patch any issues you're facing I'm almost sure! I'm sorry I can't be of more help to you :( |
Alright, thanks for the suggestion, I will check it out |
Is your feature request related to a problem? Please describe.
I tried creating 2 apps within nestjs and using the shard manager to instantiate the other, but I keep getting an error,
SHARDING_READY_TIMEOUT Shard 0's Client took too long to become ready.
.Describe the solution you'd like
I'd like to be able to specify within the config the sharding requirements and have it all handled behind the scenes.
Describe alternatives you've considered
I've tried creating a single file I could specify in the sharding manager and a separate nestjs app under a monorepo with no success.
The text was updated successfully, but these errors were encountered: