Additional information

TIP

This page is a follow-up and bases its code off of the previous page.

Here are some extra topics covered about sharding that you might have concerns about.

Legend

  • manager is an instance of ShardingManager, e.g. const manager = new ShardingManager(file, options);
  • client.shard refers to the current shard.

Shard messages

In order for shards to communicate, they must send messages to one another, as they are each their own process. You can listen for these messages by adding the following listener in your index.js file:

manager.on('message', (shard, message) => {
	console.log(`Shard[${shard.id}] : ${message._eval} : ${message._result}`);
});

As the property names imply, the _eval property is what the shard is attempting to evaluate, and the _result property is the output of said evaluation. However, these properties are only guaranteed if a shard is sending a message. There will also be an _error property, should the evaluation have thrown an error.

You can also send messages via process.send('hello'), which would not contain the same information. This is why the .message property's type is declared as * in the discord.js documentation.

Specific shards

There might be times where you want to target a specific shard. An example would be to kill a specific shard that isn't working as intended. You can achieve this by taking the following snippet (in a command, preferably):

client.shard.broadcastEval('if (this.shard.id === 0) process.exit();');

If you're using something like PM2 or Forever, this is an easy way to restart a specific shard. Remember, Shard#BroadcastEval sends a message to all shards, so you have to check if it's on the shard you want.

ShardingManager#shardArgs

Consider the following example of creating a new ShardingManager instance:

const manager = new ShardingManager('./bot.js', {
	shardArgs: ['--ansi', '--color', '--trace-warnings'],
	token: 'your-token-goes-here',
});

The shardArgs property is what you would normally pass in if you executed your bot process without sharding, e.g.:

node bot.js --ansi --color --trace-warnings

Should you need them for whatever reason, they're available in process.argv property, which contains an array of command-line arguments used to execute the script.

Eval arguments

There may come a point where you will want to pass functions or arguments from the outer scope into a .broadcastEval() call.

client.shard.broadcastEval(`(${funcName})('${arg}')`);

In this small snippet, an entire function is being passed to the eval. It needs to be encased in parenthesis; it will throw errors on its way there otherwise. Another set of parenthesis is needed so the function actually gets called. Finally, the passing of the argument itself, which slightly varies, depending on the type of argument you are passing. If it's a string, you must wrap it in quotes, or it will be interpreted as is and will throw a syntax error, because it won't be a string by the time it gets there.

Now, what if you wanted to call a function from within the client context? That is to say, you are not passing a function. It would look something like this:

client.shard.broadcastEval(`this.${funcName}(${args});`);

This would become client.funcName(args) once it gets through. This is handy if you, for example, have extended your client object with your own class and wish to call some of its methods manually.

Asynchronous functions

There may be a time when you want to have your shard process an asynchronous function. Here's how you can do that!

client.shard.broadcastEval(`
	let channel = this.channels.get('id');
	let msg;
	if (channel) {
		msg = channel.fetchMessage('id').then(m => m.id);
	}
	msg;
`);

This snippet allows you to return fetched messages outside of the broadcastEval, allowing you to know whether or not you were able to retrieve a message, for example. Remember, you aren't able to return entire objects outside. Now, what if we wanted to use async/await syntax inside?

client.shard.broadcastEval(`
	(async => {
		let channel = this.channels.get('id');
		let msg;
		if (channel) {
			msg = await channel.fetchMessage('id').then(m => m.id);
		}
		return msg;
	})();
`);

This example will work the same, but you are able to produce cleaner code with async/await. Additionally. What this does is declare an asynchronous function and then immediately call it. As it is also the last declared line, it is effectively being returned. Remember that you need to return an item inside a function one way or another.

Sharded Bot Example(s)

If you'd like to check out a full example of sharding, here are the open-source examples we've found:

If you know of other open-source bots that are sharded and use discord.js, feel free to make a pull request!

Last Updated: 1/4/2019, 5:04:05 AM