Please describe the problem you are having in as much detail as possible:
The warnings below are constantly printed out every once in a while (it seems to be fairly random intervals). However, the numbers are always the same (in this case, 32 and 21).
(node:32) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message listeners added to [process]. Use emitter.setMaxListeners() to increase limit
(node:21) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message listeners added to [ChildProcess]. Use emitter.setMaxListeners() to increase limit
Include a reproducible code sample here, if possible:
// "index.js" would be any code that spawns a Client.
import { ShardingManager } from 'discord.js';
(async () => {
const manager = new ShardingManager('./index.js', { token: process.env.DISCORD_BOT_TOKEN });
await manager.spawn().catch(console.error);
console.log(`Spawned ${manager.shards.size} shards.`);
})();
Further details:
I believe the error is coming from %project_path%/node_modules/discord.js/sharding/ShardClientUtil.js lines 35 & 47 as it listens to both of the events that are in the warning. I don't listen to the message event in either process or ChildProcess at any time, and these warnings are never seen when I don't use sharding. This leads me to believe that's it's caused by the two lines I mentioned above.
It seems like ShardClientUtil is re-created seemingly at random - the only time I see a new instance being created is when a new Client is created, so maybe sharding re-spawns Clients for some reason or another without destroying the old one which is causing this?
f9f3661Update. I've found what's causing it.
Running broadcastEval in quick succession (11+ times) (eg. in Promise.all) will show the warning.
line 148 in ShardClientUtil.js has parent.on('message', listener);, and it removes the listener once it finishes. However, running it enough times at once will show the warning as most are still performing tasks so it just keeps adding on the listener.
Here's an MRE:
// "client" is a Discord client.
(async () => {
await Promise.all(Array.from({ length: 15 }, () =>
client.shard.broadcastEval(`(async () => {
await new Promise(r => setTimeout(r, 5000));
})();`);
));
})();
This will run broadcastEval 15 times where each just waits 5000 ms before finishing.
As the "issue" isn't really an issue that has any large negative impact it's probably fine to keep it as it is.
A way to fix it could be using a Map (or Collection) with the script as the key and the value as like { resolve, reject } (both as their respective functions). This way, you only need to listen to the message event on process once, and you can handle them as they come in.
Most helpful comment
Update. I've found what's causing it.
Running
broadcastEvalin quick succession (11+ times) (eg. in Promise.all) will show the warning.line 148 in
ShardClientUtil.jshasparent.on('message', listener);, and it removes the listener once it finishes. However, running it enough times at once will show the warning as most are still performing tasks so it just keeps adding on the listener.Here's an MRE:
This will run
broadcastEval15 times where each just waits 5000 ms before finishing.As the "issue" isn't really an issue that has any large negative impact it's probably fine to keep it as it is.
A way to fix it could be using a Map (or Collection) with the script as the key and the value as like
{ resolve, reject }(both as their respective functions). This way, you only need to listen to themessageevent onprocessonce, and you can handle them as they come in.