discordjs / discord.js

A powerful JavaScript library for interacting with the Discord API
https://discord.js.org
Apache License 2.0
25.36k stars 3.97k forks source link

djs v14 silently fails if initial gateway connection is ratelimited #8757

Closed hackermondev closed 2 years ago

hackermondev commented 2 years ago

Which package is this bug report for?

discord.js

Issue description

Discord.js v14 silents fails if initial gateway connection API endpoint (/api/v9/gateway/bot) is ratelimited.

Steps to reproduce:

  1. connect to a server where the ip is currently ratelimited
    {"code": 0, "message": "You are being blocked from accessing our API temporarily due to exceeding our rate limits frequently. Please read our docs at https://discord.com/developers/docs/topics/rate-limits to prevent this moving forward."}
  2. run a basic bot

Expected Result: It should throw an error or print something to the console Actual Result: the issue here is that discord.js doesn't return anything to the user and the program just ends abruptly. Note: On discord.js v13, it doesn't print anything to the console either (unless you're logging debug events) but it waits out the timeout. Right now, djs v14 doesn't debug anything and it doesn't print anything to the console when its ratelimited (it just closes the program)

GIF EXAMPLE: OnUc3PL7o7

Code sample

const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.on('ready', () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

client.on('interactionCreate', async interaction => {
  if (!interaction.isChatInputCommand()) return;

  if (interaction.commandName === 'ping') {
    await interaction.reply('Pong!');
  }
});

client.login(process.env['DISCORD_TOKEN']);

Package version

14.6.0

Node.js version

16.15.0

Operating system

Linux

Priority this issue should have

Low (slightly annoying)

Which partials do you have configured?

No Partials

Which gateway intents are you subscribing to?

Guilds, GuildMembers, GuildMessages, MessageContent

I have tested this issue on a development release

No response

didinele commented 2 years ago

It doesn't "fail", it waits for the ratelimit and will eventually connect. This is intended default behavior. If you would like for it to throw, you can use the rejectOnRateLimit REST option.

hackermondev commented 2 years ago

It doesn't "fail", it waits for the ratelimit and will eventually connect. This is intended default behavior. If you would like for it to throw, you can use the rejectOnRateLimit REST option.

@didinele It doesn't wait though. It exists the program immediately (check my attached GIF) And shouldn't it at least log something to debug (v13 did)? It doesn't do that either.

didinele commented 2 years ago

It doesn't wait though. It exists the program immediately (check my attached GIF)

Unfortunately, I have never seen this behavior on any version of v14 (and we see people ask about this every so often in support), nor am I able to attempt it without getting myself CF banned on purpose, which I'd rather not, but looking at the source code, the behavior you're describing seems almost certainly impossible - which would make this an issue on your end one way or another.

The call to /gateway/bot is done here: https://github.com/discordjs/discord.js/blob/4f3c13628ecaf8d22174a7a1e227bb7b8278dbb5/packages/discord.js/src/client/websocket/WebSocketManager.js#L134-L141

And the error is funneled here: https://github.com/discordjs/discord.js/blob/4f3c13628ecaf8d22174a7a1e227bb7b8278dbb5/packages/discord.js/src/client/Client.js#L231-L237

Notice how if an error was encountered, we do just outright throw it, but in the case of any 429 the request is just re-queued:

https://github.com/discordjs/discord.js/blob/4f3c13628ecaf8d22174a7a1e227bb7b8278dbb5/packages/rest/src/lib/handlers/SequentialHandler.ts#L475-L476

And shouldn't it at least log something to debug (v13 did)? It doesn't do that either.

No, it's outside of the core library's space. If you want debug logs, listen to them from <Client>#rest

HRK44 commented 2 years ago

Experienced the same issue here https://github.com/discordjs/discord.js/issues/8623

hackermondev commented 2 years ago

@didinele I did some digging and I found what was causing the issue.

https://github.com/discordjs/discord.js/blob/4f3c13628ecaf8d22174a7a1e227bb7b8278dbb5/packages/rest/src/lib/handlers/SequentialHandler.ts#L463

This line basically is telling the program to wait for the ratelimit to finish. The ref option is set to true and that is what is causing the issue.

If we look back at node documentation (https://nodejs.org/api/timers.html#timerspromisessetintervaldelay-value-options), we can see what the ref option does.

ref Set to false to indicate that the scheduled Timeout between iterations should not require the Node.js event loop to remain active. Default: true.

So, what is happening is that the timeouts don't require the event loop to remain active and then because there's nothing else going on (no open gateway connection), the program exists and the timeout doesn't correctly work.

I've went ahead and created a pull request to fix this: #8779