Giter Club home page Giter Club logo

discord-hybrid-sharding's Introduction

Discord server

Discord-Hybrid-Sharding

Scale your bot efficiently with hybrid sharding — combining process and internal sharding (m shards on n processes) for minimizing your resource usage.

Battle-tested against bots managing up to 600k Guilds, reducing resource overhead (process idle usage) by 40-60% versus common sharding managers (discord.js). Works seamlessly with any Discord framework.

Featured by Discord Creators

Private Community for Verified Bot Developers. Meet large and small bot developers and have a nice exchange...

Why?

Imagine this: if you used the djs sharding manager for 14 shards, your bot would consume around 200MB*14=2.8GB of RAM when idle. On the other hand, hosting all shards in one process would only use about 200MB (idle process usage). However, once your bot grows beyond 22,000 guilds, internal sharding becomes less efficient, leading to performance issues as one process handles a large number of events. Why not combine the best of both worlds to efficiently scale up your bot? This approach has been standard practice for large bots for years. Plus, with customizable parameters for processes and shards, you can optimize it to fit your specific needs.

  • Easy migration from other ShardingMangers (Djs, Eris and co) like the one from djs (just renaming)
  • Seamless ReClustering/ReSharding/Restarts
  • Decentralized BroadCastEval function for listenerless operation, minimizing memory leaks and the need of the client to be ready
  • Heartbeat System to automatically respawn unresponsive or dead ClusterClients
  • IPC System enabling communication between Client and ClusterManager via .request(), .reply(), .send() methods
  • Precise control over cluster queue with methods like manager.queue.next(), .stop(), .resume()
  • Memory efficiency resulting in 40-60% less memory consumption during clustering
  • Detailed event debugging providing comprehensive cluster information
  • Additional functions like evalOnManager for more control
  • Support for string and functions with context in .broadcastEval()
  • Optional timeout feature in .broadcastEval() to mitigate memory leaks and unresponsiveness
  • Cross-Hosting Support: Manage Shards/Clusters across machines and facilitate cross-host communication (IPC, .broadcastEval())

    Hybrid-Sharding handles threading logic, while your chosen library manages other aspects. Note: Ratelimits won't sync across clusters; consider using a rest proxy like (@discordjs/rest, nirn-proxy, ...)

How does it work?

The system utilizes clusters or master shards, similar to regular shards in a sharding manager. These clusters can spawn internal shards, reducing the need for as many regular shards. For example, in a Discord bot with 4000 guilds, instead of spawning 4 shards with the Sharding Manager (approximately 4 x 200MB memory on idle), we start with 2 clusters/master shards, each spawning 2 internal shards. This results in a saving of 2 shards compared to the regular Sharding Manager (approximately 2 x 200MB memory).

If you need help, feel free to join following discord server.

Getting Started

1. Installation

npm i discord-hybrid-sharding

2. Setup

Create the cluster.js file, which will contain the ClusterManager for managing the processes/clusters.

// Typescript: import { ClusterManager } from 'discord-hybrid-sharding'
const { ClusterManager } = require('discord-hybrid-sharding');

const manager = new ClusterManager(`${__dirname}/bot.js`, {
    totalShards: 'auto', // or numeric shard count
    /// Check below for more options
    shardsPerClusters: 2, // 2 shards per process
    // totalClusters: 7,
    mode: 'process', // you can also choose "worker"
    token: 'YOUR_TOKEN',
});

manager.on('clusterCreate', cluster => console.log(`Launched Cluster ${cluster.id}`));
manager.spawn({ timeout: -1 });

Refactor your main bot.js file and provide the sharding parameters to your discord.js client.

// Typescript: import { ClusterClient, getInfo } from 'discord-hybrid-sharding'
const { ClusterClient, getInfo } = require('discord-hybrid-sharding');
const Discord = require('discord.js');

const client = new Discord.Client({
    shards: getInfo().SHARD_LIST, // An array of shards that will get spawned
    shardCount: getInfo().TOTAL_SHARDS, // Total number of shards
});

client.cluster = new ClusterClient(client); // initialize the Client, so we access the .broadcastEval()
client.login('YOUR_TOKEN');

3. Start

Start your project by running node cluster.js, which will start the ClusterManager and start spawning the processes.

Quick Overview

Evaling over clusters

Following examples assume that your Discord.Client is called client.

client.cluster
    .broadcastEval(`this.guilds.cache.size`)
    .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`));

// or with a callback function
client.cluster
    .broadcastEval(c => c.guilds.cache.size)
    .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`));

ClusterManager

Option Type Default Description
totalShards number or string "auto" Amount of internal shards which will be spawned
totalClusters number or string "auto" Amount of processes/clusters which will be spawned
shardsPerClusters number or string - Amount of shards which will be in one process/cluster
shardList Array[number] - OPTIONAL - On cross-hosting or spawning specific shards you can provide a shardList of internal Shard IDs, which will get spawned
mode "worker" or "process" "worker" ClusterManager mode for the processes
token string - OPTIONAL -Bot token is only required totalShards are set to "auto"

The Manager.spawn options are the same as for Sharding Manager

Cluster Events

Event Description
clusterCreate Triggered when a cluster gets spawned
clusterReady Triggers if the client has fired the ready event for that cluster

Cluster Client Properties

All properties like the ones for .broadcastEval() are available, just replace the client.shard with client.cluster Other properties:

Property Description
client.cluster.count Returns the amount of all clusters
client.cluster.id Returns the current cluster ID
client.cluster.ids Returns all internal shards of the cluster

Changes | Migrating to Discord-Hybrid-Sharding

Options are now labeled as cluster instead of shard:

- client.shard...
+ client.cluster...

- .broadcastEval((c, context) => c.guilds.cache.get(context.guildId), { context: { guildId: '1234' }, shard: 0 })
+ .broadcastEval((c, context) => c.guilds.cache.get(context.guildId), { context: { guildId: '1234' }, cluster: 0 })

Small changes in naming conventions:

- client.shard.respawnAll({ shardDelay = 5000, respawnDelay = 500, timeout = 30000 })
+ client.cluster.respawnAll({ clusterDelay: 5000, respawnDelay: 5500, timeout: 30000 })

- manager.shard.respawnAll({ shardDelay = 5000, respawnDelay = 500, timeout = 30000 })
+ manager.respawnAll({ clusterDelay: 5000, respawnDelay: 5500, timeout: 30000 })

Get current cluster ID:

- client.shard.id
+ client.cluster.id

Get current shard ID:

- client.shard.id
+ message.guild.shardId

Get total shards count:

- client.shard.count
+ client.cluster.info.TOTAL_SHARDS

Get all ShardID's in the current cluster:

- client.shard.id
+ [...client.cluster.ids.keys()]

New Features

Zero Downtime Reclustering:

Zero Downtime Reclustering is a Plugin, which is used to reshard/recluster or even restart your bot with having a theoretical outage of some seconds. There are two options for the restartMode:

  • gracefulSwitch: Spawns all new Clusters with the provided Info in maintenance mode, once all clusters have been spawned and the DiscordClient is ready, the clusters will exit maintenance mode, where as it will fire the client.cluster.on('ready') event. In order to load the Database and listen to events. Moreover all Clusters will be gracefully killed, once all clusters exited maintenance mode.
  • rolling: Spawns the Clusters with the provided Info in maintenance mode, once the DiscordClient is ready of the Cluster, the Cluster will exit maintenance mode, where as it will fire the client.cluster.on('ready') event. In order to load the Database and listen to events. Moreover the OldCluster will be killed, since the Cluster has exited maintenance mode. Not recommended, when shardData has not been updated.

Cluster.js

// Typescript: import { ClusterManager, ReClusterManager  } from 'discord-hybrid-sharding'
const { ClusterManager, ReClusterManager } = require('discord-hybrid-sharding');
const manager = new ClusterManager(`${__dirname}/bot.js`, {...});

manager.extend(
    new ReClusterManager()
)
... ///SOME CODE
// Start reclustering
const optional = {totalShards, totalClusters....}
manager.recluster?.start({restartMode: 'gracefulSwitch', ...optional})

Bot.js

// Typescript: import { ClusterClient, getInfo } from 'discord-hybrid-sharding'
const { ClusterClient, getInfo } = require('discord-hybrid-sharding');
const client = new Discord.Client(...)
client.cluster = new ClusterClient(client);

if (client.cluster.maintenance) console.log(`Bot on maintenance mode with ${client.cluster.maintenance}`);

client.cluster.on('ready', () => {
    // Load Events
    // Handle Database stuff, to not process outdated data
});

client.login(token);

HeartbeatSystem

  • Checks if Cluster/Client sends a heartbeat on a given interval
  • When the Client doesn't send a heartbeat, it will be marked as dead/unresponsive
  • Cluster will get respawned after the given amount of missed heartbeats has been reached
// Typescript: import { ClusterManager, HeartbeatManager  } from 'discord-hybrid-sharding'
const { ClusterManager, HeartbeatManager } = require('discord-hybrid-sharding');
const manager = new ClusterManager(`${__dirname}/bot.js`, {...});

manager.extend(
    new HeartbeatManager({
        interval: 2000, // Interval to send a heartbeat
        maxMissedHeartbeats: 5, // Maximum amount of missed Heartbeats until Cluster will get respawned
    })
)

Control Restarts

  • Cap the amount of restarts per cluster to a given amount on a given interval
const manager = new ClusterManager(`${__dirname}/bot.js`, {
    ...YourOptions,
    restarts: {
        max: 5, // Maximum amount of restarts per cluster
        interval: 60000 * 60, // Interval to reset restarts
    },
});

IPC System

  • The IPC System allows you to listen to your messages
  • You can communicate between the cluster and the client
  • This allows you to send requests from the client to the cluster and reply to them and vice versa
  • You can also send normal messages which do not need to be replied

ClusterManager | cluster.js

// Typescript: import { ClusterManager, messageType } from 'discord-hybrid-sharding'
const { ClusterManager, messageType } = require('discord-hybrid-sharding');
const manager = new ClusterManager(`${__dirname}/testbot.js`, {
    totalShards: 1,
    totalClusters: 1,
});

manager.on('clusterCreate', cluster => {
    cluster.on('message', message => {
        console.log(message);
        if (message._type !== messageType.CUSTOM_REQUEST) return; // Check if the message needs a reply
        message.reply({ content: 'hello world' });
    });
    setInterval(() => {
        cluster.send({ content: 'I am alive' }); // Send a message to the client
        cluster.request({ content: 'Are you alive?', alive: true }).then(e => console.log(e)); // Send a message to the client
    }, 5000);
});
manager.spawn({ timeout: -1 });

ClusterClient | client.js

// Typescript: import { ClusterClient, getInfo, messageType } from 'discord-hybrid-sharding'
const { ClusterClient, getInfo, messageType} = require('discord-hybrid-sharding');
const Discord = require('discord.js');
const client = new Discord.Client({
    shards: getInfo().SHARD_LIST, // An array of shards that will get spawned
    shardCount: getInfo().data.TOTAL_SHARDS, // Total number of shards
});

client.cluster = new ClusterClient(client);
client.cluster.on('message', message => {
    console.log(message);
    if (message._type !== messageType.CUSTOM_REQUEST) return; // Check if the message needs a reply
    if(message.alive) message.reply({ content: 'Yes I am!' }):
});
setInterval(() => {
    client.cluster.send({ content: 'I am alive as well!' });
}, 5000);
client.login('YOUR_TOKEN');

Control Cluster queue:

With a complex code-base, you probably need a fine-grained control over the cluster spawn queue in order to respect rate limits.

The queue system can be controlled from the cluster manager.

const manager = new ClusterManager(`${__dirname}/bot.js`, {
    totalShards: 8,
    shardsPerClusters: 2,
    queue: {
        auto: false,
    },
});

The auto property is set with true by default, which automatically queues the clusters, when running manager.spawn()

When the auto mode has been disabled, then you have to manually manage the queue.

Cluster.js

manager.spawn();
manager.queue.next();

The manager.queue.next() function will spawn the next cluster in the queue. Now you can call the function client.cluster.spawnNextCluster() from the client to spawn the next cluster.

Property Description
manager.queue.start() Starts the queue and resolves, when the queue is empty
manager.queue.stop() Stops the queue and blocks all .next requests
manager.queue.resume() Resumes the queue and allows .next requests again
manager.queue.next() Spawns the next cluster in the queue
client.cluster.spawnNextCluster() Triggers the spawn of the next cluster in the queue

Other Features:

Evaluates a script on the ClusterManager:

client.cluster.evalOnManager('process.memoryUsage().rss / 1024 ** 2');

Listen to debug messages and internal stuff:

manager.on('debug', console.log);

Optional Timeout on broadcastEval (Promise will get rejected after given time):

client.cluster.broadcastEval('new Promise((resolve, reject) => {})', { timeout: 10000 });

Open a PR/Issue when you need other Functions :)

Usage with other libraries

Using the package with other libraries requires some minor changes:

  • The Cluster.js will stay the same, scroll up to get the Code
  • Your Bot.js file will have some additional code
// Typescript: import { ClusterClient, getInfo } from 'discord-hybrid-sharding'
const { ClusterClient, getInfo } = require('discord-hybrid-sharding');

///Create your Discord Client:
/* Use the Data below for telling the Client, which shards to spawn */
const lastShard = getInfo().LAST_SHARD_ID;
const firstShard = getInfo().FIRST_SHARD_ID;
const totalShards = getInfo().TOTAL_SHARDS;
const shardList = getInfo().SHARD_LIST;

client.cluster = new ClusterClient(client);

///When the Client is ready, You can listen to the client's ready event:
// Just add, when the client.on('ready') does not exist
client.cluster.triggerReady();

The upper code is a pseudo code and shows how you can use this package with other libraries

With some minor changes, you can even use this Package for clustering normal processes.

Bugs, Glitches and Issues

If you encounter any problems feel free to open an issue in our gitHub repository or join the discord server.

Credits

Credits goes to the discord.js library for the base code (See changes.md) and to this helpful server

discord-hybrid-sharding's People

Contributors

gygi4 avatar meister03 avatar pcfan avatar tysonop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

discord-hybrid-sharding's Issues

This module doesn't support ts-node?

Describe the bug
My bot is wrote in typescript and I run the cluster file with ts-node Cluster.ts and my console output cannot use import outside a module

(To Reproduce)

Expected behavior
The bot started successfully

Screenshots & Error Stack

> ts-node Cluster.ts
Cluster 0 was created!
(node:343) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/mnt/c/Users/Kay/Desktop/KayBotTypeScriptJDA/src/index.ts:1
import Client from "./Client";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:352:18)
    at wrapSafe (node:internal/modules/cjs/loader:1026:15)
    at Module._compile (node:internal/modules/cjs/loader:1061:27)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47

Node.js v17.4.0

Discord.js Version

Types Error on .map

Describe the bug
A clear and concise description of what the bug is.

When i do client.cluster.ids.map() return types error.

(To Reproduce)

Expected behavior
A clear and concise description of what you expected to happen.

Mapping che ids

Screenshots & Error Stack
If applicable, add screenshots to help explain your problem.

This expression is not callable.
Each member of the union type '(<U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) =>
 U[])|{ <T>(fn: (value: WebSocketShard, key: number, collection: Collection<number, WebSocketShard>) => T): T[]; 
<This, T>(fn: (this: This, value: WebSocketShard, key: number, collection: Collection<...>) => T, thisArg: This): ...'
 has signatures, but none of those signatures are compatible with each other.ts(2349)

Discord.js Version

  • 14.7.1

`ConnectTimeoutError`

Describe the bug
I hope the screenshot explains enough, because I am not entirely sure why I am getting this error.
I started getting this error approximately 3 weeks ago, before that I have never gotten it.

(To Reproduce)

Expected behavior
No error 😅

Screenshots & Error Stack
image

Discord.js Version

  • Latest (14.15.2)

Additional context
So I don't know, but could it be caused by slow internet. In that case is there a way to increase the timeout and if so would that be a proper solution?

Reclustering makes all clusters enter maintenance mode

Describe the bug
If all of the clusters become maintenance mode, it can't achieve zero-downtime reclustering.

Expected behavior
The existing clusters should run until the new clusters become ready.

Screenshots & Error Stack
image

Discord.js Version

  • 14.3.0

BUG

Discord JS v13,
image
image

I did everything correct i changed package json index to the shard file with the stuff and put my index file in there i added the stuff in the new client and get this error

Cannot read "cache" of undefined

After about an hour with the clister on, the process exits qith this error.

node:internal/event_target:646
2022-03-26T12:51:20.091867+00:00 app[worker.1]:   process.nextTick(() => { throw err; });
2022-03-26T12:51:20.091868+00:00 app[worker.1]:                            ^
2022-03-26T12:51:20.094581+00:00 app[worker.1]: TypeError [Error]: Cannot read property 'cache' of undefined
2022-03-26T12:51:20.094583+00:00 app[worker.1]:     at MessageCreateAction.handle (/app/node_modules/discord.js/src/client/actions/MessageCreate.js:13:41)
2022-03-26T12:51:20.094585+00:00 app[worker.1]:     at Object.module.exports [as MESSAGE_CREATE] (/app/node_modules/discord.js/src/client/websocket/handlers/MESSAGE_CREATE.js:4:32)
2022-03-26T12:51:20.094586+00:00 app[worker.1]:     at WebSocketManager.handlePacket (/app/node_modules/discord.js/src/client/websocket/WebSocketManager.js:350:31)
2022-03-26T12:51:20.094587+00:00 app[worker.1]:     at WebSocketShard.onPacket (/app/node_modules/discord.js/src/client/websocket/WebSocketShard.js:443:22)
2022-03-26T12:51:20.094587+00:00 app[worker.1]:     at WebSocketShard.onMessage (/app/node_modules/discord.js/src/client/websocket/WebSocketShard.js:300:10)
2022-03-26T12:51:20.094588+00:00 app[worker.1]:     at WebSocket.onMessage (/app/node_modules/ws/lib/event-target.js:199:18)
2022-03-26T12:51:20.094588+00:00 app[worker.1]:     at WebSocket.emit (node:events:394:28)
2022-03-26T12:51:20.094589+00:00 app[worker.1]:     at Receiver.receiverOnMessage (/app/node_modules/ws/lib/websocket.js:1098:20)
2022-03-26T12:51:20.094589+00:00 app[worker.1]:     at Receiver.emit (node:events:394:28)
2022-03-26T12:51:20.094589+00:00 app[worker.1]:     at Receiver.dataMessage (/app/node_modules/ws/lib/receiver.js:528:14)
2022-03-26T12:51:20.094590+00:00 app[worker.1]: Emitted 'error' event on ClusterManager instance at:
2022-03-26T12:51:20.094590+00:00 app[worker.1]:     at Cluster._handleError (/app/node_modules/discord-hybrid-sharding/src/Core/Cluster.js:538:22)
2022-03-26T12:51:20.094590+00:00 app[worker.1]:     at Worker.emit (node:events:394:28)
2022-03-26T12:51:20.094591+00:00 app[worker.1]:     at Worker.[kOnErrorMessage] (node:internal/worker:298:10)
2022-03-26T12:51:20.094591+00:00 app[worker.1]:     at Worker.[kOnMessage] (node:internal/worker:309:37)
2022-03-26T12:51:20.094592+00:00 app[worker.1]:     at MessagePort.<anonymous> (node:internal/worker:210:57)
2022-03-26T12:51:20.094592+00:00 app[worker.1]:     at MessagePort.[nodejs.internal.kHybridDispatch] (node:internal/event_target:460:20)
2022-03-26T12:51:20.094592+00:00 app[worker.1]:     at MessagePort.exports.emitMessage (node:internal/per_context/messageport:23:28)

I followed the example as it is and tried everything to solve the problem but still no success on avoiding this behaviour.

Discord.js Version

Additional context

Multiserver support?

Hey, idk the future of the project, but I was wondering if you could implement horizontal scaling by having like multiple vps's as slaves?

Not enough sessions remaining to spawn 1 shards; only 0 remaining

Describe the bug
I don't know if there's a bug on it but when i try to start my bot appears a warning that it says "Not Enough Sessions to spawn 1"

(To Reproduce)

Expected behavior
Early days before this error, the bot was working perfectly, but the bot just don't start as extected.

Screenshots & Error Stack
image

Discord.js Version

  • 14.11.0

Additional context
i don't have any other context to say

Get rate limited when login to the bot.

I have an issue that when adding sharding system in my bot I always login to the bot 2 times and get rate limited, how to fix this? Here is my code file:

index.js:

const Cluster = require('discord-hybrid-sharding');
require("dotenv").config();
const logger = require('./plugins/logger.js')

const manager = new Cluster.Manager(`./main/login.js`, {
    totalShards: 'auto', // or 'auto'
    shardsPerClusters: 2,
    mode: 'process', // you can also choose "worker"
    token: process.env.TOKEN,
});

manager.on('clusterCreate', cluster => logger.info(`Launched Cluster ${cluster.id}`));
manager.spawn({ timeout: -1 });

login.js

const MainClient = require("./bot.js");
const client = new MainClient();

client.connect()
module.exports = client; 

bot.js

const { Client, Intents, Collection } = require("discord.js");
const { Manager } = require("erela.js");
const Spotify = require("erela.js-spotify")
const Deezer = require("../plugins/Deezer");
const AppleMusic = require("erela.js-apple")
const Facebook = require("erela.js-facebook");
const { I18n } = require("locale-parser")
const Cluster = require('discord-hybrid-sharding');

class MainClient extends Client {
     constructor() {
        super({
          shards: Cluster.data.SHARD_LIST,
          shardCount: Cluster.data.TOTAL_SHARDS,
            allowedMentions: {
                parse: ["roles", "users", "everyone"],
                repliedUser: false
            },
            intents: [
                Intents.FLAGS.GUILDS,
                Intents.FLAGS.GUILD_VOICE_STATES,
                Intents.FLAGS.GUILD_MESSAGES,
            ]
        });
    this.config = require("../plugins/config.js");
    this.owner = this.config.OWNER_ID;
    this.dev = this.config.DEV_ID;
    this.color = this.config.EMBED_COLOR;
    this.i18n = new I18n(this.config.LANGUAGE);
    if(!this.token) this.token = this.config.TOKEN;
    const clientID = this.config.SPOTIFY_ID
    const clientSecret = this.config.SPOTIFY_SECRET

    process.on('unhandledRejection', error => console.log(error));
    process.on('uncaughtException', error => console.log(error));

	const client = this;

    this.manager = new Manager({
      nodes: this.config.NODES,
      autoPlay: true,
      plugins: [
        new Spotify({
          clientID,
          clientSecret
        }),
        new Facebook(),
        new Deezer(),
        new AppleMusic()
      ],
      send(id, payload) {
        const guild = client.guilds.cache.get(id);
        if (guild) guild.shard.send(payload);
      },
    });

    ["slash", "premiums"].forEach(x => client[x] = new Collection());
    ["loadCommand", "loadEvent", "loadDatabase", "loadPlayer" ].forEach(x => require(`../handlers/${x}`)(client));

	}
		connect() {
      return super.login(this.token);
    };
};

module.exports = MainClient;

Please connect

Hi meister03, can you send a friend request to osyed on Discord. Wanted to do a quick chat about something. Thanks.

You can close of delete this issue.

Help with setting client presence

Hii i am trying to set client's presence activity using the following code inside ready event of the djs client

client.user.setActivity(`Starting up...`, { type: "WATCHING" });

Neither the above code throw an error nor it sets the activity. I am upgrading from non-clustered client to clustered client for the first time and never had used sharding too. So please help me with how do i set the activity as in non-clustered client the code works but after clustering it doesn't

Get info is not a function

Zero Downtime Reclustering Cluster count

Describe the bug
Zero Downtime Reclustering was performed using the code below, but the number of clusters did not increase or decrease as the number of bot servers increased.
Only after completely shutting down the bot and cluster and running it again did the number of clusters increase.

manager.recluster?.start({ restartMode: "rolling" });

Expected behavior
When Zero Downtime Reclustering is in operation, as the number of bot servers increases, the number of clusters must also increase.

Discord.js Version

  • 14.14.1

Broadcast eval not working when a cluster is offline

Hello, i am trying to create an API that gets the status of my bot and it's clusters by a simple fetch request from the outside.

The issue here is that when i purposely kill/respawn a cluster like if it was restarting i cannot get the status of it because of the broadcast eval trying to eval on an offline cluster.

Error: CLUSTERING_NO_CHILD_EXISTS | ClusterId: 0
    at Cluster.eval (/home/bots/mrkayjaydee/xinko-ts/node_modules/discord-hybrid-sharding/dist/Core/Cluster.js:226:35)
    at ClusterManager._performOnClusters (/home/bots/mrkayjaydee/xinko-ts/node_modules/discord-hybrid-sharding/dist/Core/ClusterManager.js:366:37)
    at ClusterManager.broadcastEval (/home/bots/mrkayjaydee/xinko-ts/node_modules/discord-hybrid-sharding/dist/Core/ClusterManager.js:320:21)
    at ClusterHandler.handleMessage (/home/bots/mrkayjaydee/xinko-ts/node_modules/discord-hybrid-sharding/dist/Structures/IPCHandler.js:28:18)
    at Cluster._handleMessage (/home/bots/mrkayjaydee/xinko-ts/node_modules/discord-hybrid-sharding/dist/Core/Cluster.js:247:42)
    at ChildProcess.emit (node:events:513:28)
    at emit (node:internal/child_process:937:14)
    at process.processTicksAndRejections (node:internal/process/task_queues:83:21)

Cluster file

import { ClusterManager } from "discord-hybrid-sharding";
import clientToken from "./config";
import log from "./utils/logger";

const manager = new ClusterManager(`${__dirname}/index.js`, {
	totalShards: 2,
	shardsPerClusters: 1,
	mode: "process",
	token: clientToken.token,
});

manager.on("clusterCreate", (cluster) =>
	log(
		`Launched Cluster ${cluster.id}\n-------------------------------------------------------------`,
		"cluster"
	)
);
manager.spawn({ timeout: -1 });

Here is my code that is working but not with an offline cluster, i wanna know if it's possible for each shards/cluster to get the status of it like: online, offline, reconnecting etc.

import Xinko from "./structures/Client";

const express = require("express");
const app = express();
const cors = require("cors");
const port = process.env.PORT || 8362;
import config from "./config";

let authToken = `Bot ${config.token}`;

let authTokenMiddleware = (req: any, res: any, next: any) => {
	if (req.headers.authorization === authToken) {
		next();
	} else {
		res.status(401).send("Unauthorized");
	}
};

(BigInt.prototype as any).toJSON = function () {
	return this.toString();
};

const startServer = async (client: Xinko) => {
	app.use(cors());
	app.get("/commands", authTokenMiddleware, (req: any, res: any) => {
		res.json(client.commands);
	});

	app.get("/stats", authTokenMiddleware, async (req: any, res: any) => {
		let guilds = await client.cluster.broadcastEval((c: any, context: any) => c.guilds.cache.size).then((guilds: any) => {
			return guilds.reduce((acc: any, guild: any) => acc + guild, 0);
		}).catch((err: any) => {
			console.log(err);
		});
		let users = await client.cluster.broadcastEval((c: any, context: any) => c.users.cache.size).then((users: any) => {
			return users.reduce((acc: any, user: any) => acc + user, 0);
		}).catch((err: any) => {
			console.log(err);
		});
		res.json({
			commands: client.commands.size,
			guilds: guilds,
			users: users,
			uptime: client.uptime,
			memory: process.memoryUsage().heapUsed,
			avatar_url: client.user.displayAvatarURL({ forceStatic: false }),
			latency: client.ws.ping,
			// for each cluster of shardList, get their infos
			shards: await client.cluster.broadcastEval((c: any, context: any) => {
				return {
					id: c.cluster.id,
					guilds: c.guilds.cache.size,
					uptime: c.uptime,
					latency: c.ws.ping,
					memory: process.memoryUsage().heapUsed,
				};
			}),
		});
	});

	app.listen(port, () => {
		console.log(`Xinko API listening at http://localhost:${port}`);
	});
};

export default startServer;

Here is the result when you GET to /stats

{
    "commands": 68,
    "guilds": 9,
    "users": 112,
    "uptime": 28849,
    "memory": 31779648,
    "avatar_url": "https://cdn.discordapp.com/avatars/688495620989780002/17ae074b5fd4201dbcb94965a9b5cd9b.webp",
    "latency": 92,
    "shards": [
        {
            "id": 0,
            "guilds": 6,
            "uptime": 35720,
            "latency": 91,
            "memory": 32802176
        },
        {
            "id": 1,
            "guilds": 3,
            "uptime": 28850,
            "latency": 92,
            "memory": 31821240
        }
    ]
}

npm ls:

[email protected] /home/bots/mrkayjaydee/xinko-ts
├── @napi-rs/[email protected]
├── @tsconfig/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @types/[email protected]
├── @typescript-eslint/[email protected]
├── @typescript-eslint/[email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
├── [email protected]
└── [email protected]

Please tell me if you need more infos ^^

Add more events

Is your feature request related to a problem? Please describe.
I wanted to have more data like what's going on with clusters

Describe the solution you'd like
Some thing like

<Manager>.on('clusterDisconnect', cluster => {
    <Client>.clusters.get(cluster.id).reconnect(timeout);
});

and few more events for clusters

Describe alternatives you've considered
Nope

Additional context
Nope

Issues with ClusterManager

Describe the bug
The issue I am having it when trying to run my bot on discord-hybrid-sharding I am now getting this error "throw new Error('NO CHILD/MASTER EXISTS OR SUPPLIED CLUSTER_MANAGER_MODE IS INCORRECT');" But this was working before? I see we are on a new update V2.1.4 is this a new common issue? :)

Screenshots & Error Stack
https://beta.cordx.lol/users/324646179134636043/zITYLhA0.png

Discord.js Version

  • Discord V14.14.1

Additional context
Just unsure if anyone else is having this issue, Any help would be greatful.

Property 'data' does not exist on type 'typeof import("discord-hybrid-sharding")'.

Error
Property 'data' does not exist on type 'typeof import("discord-hybrid-sharding")'.

Code

import Cluster from 'discord-hybrid-sharding';
import initialize from './initializer';

const Client = new Amandine({
    shards: Cluster.data.SHARD_LIST,
    shardCount: Cluster.data.TOTAL_SHARDS
});

Package.json

{
  "name": "amandine-ts",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "rm -rf dist && tsc",
    "start": "node dist/Cluster.js",
    "watch": "rm -rf dist/database/schemas && cp -r src/database/schemas dist/database/schemas && tsc --watch",
    "dev": "tsc && node dist/cluster.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@tsconfig/node16": "^1.0.2",
    "@types/figlet": "^1.5.4",
    "@types/i18next-fs-backend": "^1.1.2",
    "@types/node": "^16.11.41",
    "@types/superagent": "^4.1.15",
    "eslint": "^8.18.0",
    "typescript": "^4.7.4"
  },
  "dependencies": {
    "@discordjs/rest": "^0.4.1",
    "chartjs-node-canvas": "^4.1.6",
    "date-and-time": "^2.3.1",
    "discord-api-types": "^0.33.0",
    "discord-hybrid-sharding": "^1.6.2",
    "discord.js": "^13.7.0",
    "discord.js-light": "^4.7.0",
    "dotenv": "^16.0.0",
    "figlet": "^1.5.2",
    "i18next": "^21.8.10",
    "i18next-fs-backend": "^1.1.4",
    "ioredis": "^5.0.4",
    "mysql2": "^2.3.3",
    "stripe": "^9.11.0",
    "superagent": "^8.0.0"
  }
}

Additional context
Just updated to the latest version of discord-hybrid-sharding and got this error, working great before the update.

test issue

Describe the bug
A clear and concise description of what the bug is.

(To Reproduce)

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots & Error Stack
If applicable, add screenshots to help explain your problem.

Discord.js Version

  • [Give your Discord.js Version]

Additional context
Add any other context about the problem here.

got CLUSTER ALREADY SPAWNED when respawnAll or respawn

Describe the bug
got CLUSTER ALREADY SPAWNED when respawnAll or respawn

discord-hybrid-sharding\dist\Core\Cluster.js:113:19)
discord-hybrid-sharding\dist\Core\Cluster.js:184:21)

(To Reproduce)

Expected behavior
using client.cluster.respawnAll({ clusterDelay: 5000, respawnDelay: 5500, timeout: 30000 })

Screenshots & Error Stack
If applicable, add screenshots to help explain your problem.

Discord.js Version

  • [Give your Discord.js Version] : discord.js@^14.7.1

Additional context
Maybe HeartbeatManager have same problem, so sometime the server crash.

this.manager.shardList?.chunk is not a function

Well Heartbeatmanager not working properly

const { Manager, HeartbeatManager, ReClusterManager } = require("discord-hybrid-sharding");
const { token } = require("../settings");

const manager = new Manager("./src/bot.js", { ...options});
manager.extend( new HeartbeatManager({
  interval: 2000,
  maxMissedHeartbeats: 5,
}), new ReClusterManager)

manager.recluster.start({
  restartMode: 'gracefulSwitch',
  totalShards: "auto",
  totalClusters: 1
})

Error is here

D:\Real_Main\node_modules\discord-hybrid-sharding\src\Plugins\ReCluster.js:53
            this.manager.shardClusterList = this.manager.shardList?.chunk(
                                                                    ^

TypeError: this.manager.shardList?.chunk is not a function
    at ReClusterManager.start (D:\Real_Main\node_modules\discord-hybrid-sharding\src\Plugins\ReCluster.js:53:69)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)```

Multi-core sharding

Is your feature request related to a problem? Please describe.
Implement multi-core sharding using the cluster module

Describe the solution you'd like
Would it be possible to implement support for multi-core systems by using the cluster module to fork child processes?

Mistyped DJsClient on typings.d.ts file

Describe the bug
it's not a bug, it's a mistyped word.
Typescript will throw an error.

Expected behavior
DJSClient to be DJsClient or vice versa.

Discord.js Version

  • 13.6.0

Mistyped public access modifier

Describe the bug

Invalid public modifier on interface Queue

export interface Queue {
options: {
auto?: boolean;
timeout?: number;
};
queue: object[];
public start(): Promise<void>;
public stop(): Queue;
public resume(): Queue;
public add(item: any): Queue;
public next(): Promise<void>;
}

Screenshots & Error Stack
image

Discord.js Version
13.6.0

Example in README not working

Describe the bug
A clear and concise description of what the bug is.

client.cluster
    .broadcastEval(c => c.guilds.cache.size)
    .then(results => console.log(`${results.reduce((prev, val) => prev + val, 0)} total guilds`));

This example doesn't print out anything. I cannot get the total guilds in version 2.1.9

Expected behavior

That "6 total guilds" is printed to the console

Discord.js Version

  • discord-hybrid-sharding: 2.1.9
  • discord.js: 14.14.1

I'm also using bun in a turborepo.

My code: https://github.com/SiebeBaree/Coinz/blob/development/apps/bot/src/bot.ts

ClusterManager is not a constructor

Describe the bug
iI get "ClusterManager is not a constructor" when using p2m to run the bot.
(To Reproduce)
use form-fox and add support for discord-hybrid-sharding
Expected behavior
Bot should work
Screenshots & Error Stack
logs.txt

Discord.js Version
13.7.0

Additional context

Expose a way for the IPC system to be used for advanced users and some wrappers around it

Is your feature request related to a problem? Please describe.
I saw this library from just looking around github, and I do think it can be a good alternative for Kurasuta, but I would like some features, or exposing some internals to be used for advanced users to benefit from. While this request is made for advanced users to profit, there's no real drawback this will introduce for basic users, and will benefit both of the users.

What I ask to be considered or implemented

Describe the solution you'd like
Probably you can implement a structure for this custom ipc, where in you will track messages that is sent with receptive set to true, then track and resolve back the data to the correct cluster / context whom who sent the request. eg a cluster can have multiple .send() with receptive set to true, so ensure the data is sent properly and routed across those

Right now I modify kurasuta on its ipc to get what I wanted working, but due to veza ipc being wonky sometimes (though I didn't have crashing issues on it, but wrong responses do get routed to my clusters sometimes) which is something I don't really like, so I do hope this sharding manager do implement this on the package level so I don't need to do some structure replacement etc etc just to get custom messages and replies across all my clusters

Problem with express listening port already in use

How I would create a discord bot with dashboard + sharding.

I started it and after the first shard I got every time the error with the port is already listening.
How I can handle this with this discord-hybrid-sharding

I have a question

I wanted to know if this CLUSTERS system is efficient against RATELIMIT

why my bot catches RATELIMIT almost every week
and most Cluster systems are too complicated, broken, or not efficient.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.