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

Retry limit on HTTPError [AbortError] #3471

Closed DreamXZE closed 4 years ago

DreamXZE commented 5 years ago

Hi there,

As many people, I got time to time the HTTPError [AbortError]. It's always frustrating to get it on message.send or little api call like that, when you have another just 2 lines after that works without issue.

Describe the ideal solution A solution could be to have a 'retry' limit on the HTTPError [AbortError], as increasing the restRequestTimeout doesn't really help, because 15s is already long. I'm not observing any ping increase or a big increase of request on my server when it happened, so it looks like to be more between discord and the bot only. A retry limit could help to fix this.

Describe alternatives you've considered I did try to increase the restRequestTimeout as I said, but it seems that it still happens time to time (Like once every few days).

Thanks by advance for the answer and the consideration 😄

Deivu commented 5 years ago

AbortError exists to avoid rest requests to get stuck for a really long time. Sometimes there are requests that is taking a really long time to resolve, in some cases 2 minutes, or sometimes, doesn't even resolve at all. So instead of waiting, cancelling it for example (if it didn't resolve for 15 seconds) would be beneficial, to avoid the rest requests to get stuck.

DreamXZE commented 5 years ago

Yeah, I actually reset the value to the default one, as I see that increasing the value didn't change anything (so 15s). That's why I propose to have a retry limit. As I said, when you do two rest request one after the other, one could be stuck and the other no, for a random reason. Having a retry limit could just retry to do a new request on this error. This could also allow to decrease the restRequestTimeout, as you said because sometimes, a request is never resolved. I never see two requests get a restRequestTimeout one after the other.

vladfrangu commented 5 years ago

It's something I have considered adding in https://github.com/discordjs/discord.js/pull/3443, which would add the requests that time out at the end of the rest queue, and try it again later. I'll experiment with it later

DreamXZE commented 5 years ago

Thanks vladfrangu! I will follow your PR and see how it goes.

BannerBomb commented 5 years ago

I would like to add to this, I have noticed that once the abort method got added I have noticed that my bot has been spitting out more errors about it aborting stuff even if it only took 3 milliseconds to load. And I have had higher memory usage with it. I tested by removing the abort method and the issues have seemed to go away. But idk the memory part might just be a me issue.

Deivu commented 5 years ago

Never had leaks with AbortErrors, I run stable at 4.5-4.9gb at 7 days uptime.

DreamXZE commented 5 years ago

After braining a bit and taking a look to RequestHandler.js, isn't supposed to already retry (if a retryLimit is set)? AbortError has the error code 500 and is in the range where the retry is applied. Line 154 => 165 :

   } else if (res.status >= 500 && res.status < 600) {
      // Retry the specified number of times for possible serverside issues
      if (item.retries === this.manager.client.options.retryLimit) {
        return reject(
          new HTTPError(res.statusText, res.constructor.name, res.status, item.request.method, request.path)
        );
      } else {
        item.retries++;
        this.queue.unshift(item);
        return this.run();
      }
    }

If yes, there is something I don't get into RequestHandler.js, which it throws a first HTTPError at line 106, that is before the retryLimit check, and so kinda break the command execussion and don't really go further.

Line 99 => 108:

  let res;
    try {
      res = await request.make();
    } catch (error) {
      // NodeFetch error expected for all "operational" errors, such as 500 status code
      this.busy = false;
      return reject(
        new HTTPError(error.message, error.constructor.name, error.status, request.method, request.path)
      );
    }

... then error handler

Is the RequestHandler is supposed to send an Error for each try ? Or just one at the end of all the try?

If it's the second solution, it looks like there is something worng (or maybe it's just me who don't have enough knowledge to understand what's going on)

richgoldmd commented 5 years ago

Is there an effective way of dealing with this issue? Catching the results of send() for example should do but what if it happens when reporting an error back to the user?

channel.send(someMessage).catch((e) => channel.send('an error occurred')).catch(console.log);

?

DreamXZE commented 5 years ago

This is actually the DIY way to do it, but not efficient. Also if you have to do it for everything in your code (and not only send message that contact the discord API), it can become a nightmare.

The issue has to be resolved into the RequestHandler. Sadly as I exposed in the previous message, I don't really have the level to do it, and this post is just an enhancement proposal, maybe it can be also considered as a bug with the previous point exposed? (but it need to be read by one of the dev)

monbrey commented 5 years ago

A library shouldn't really be implementing error handling though - it does exactly what it should do and throws/rejects an Error with appropriate information to you, the developer.

Its then up to you how you want to handle errors.

Your example of sending the error to the user isn't really a great idea because as you've pointed out, doing that relies on the same API that may have thrown the error in the first place. Error handling should be doing things logging it locally for analysis, correcting any local cache etc.

DreamXZE commented 5 years ago

So, what's the point of the retryLimit if the error is already thrown and then never retry? As I pointed in this message, the AbortError number is 500 and was supposed to be retry in the actual code, but it seems to not be.

Edit : I got the confusion, by ... Error handler I don't mean it needs to add an error handler in the RequestHandler.js file, but was just talking of actual following line! Sorry for the confusion

ghost commented 4 years ago

im having the same issue while using the mute command on my bot i have error HTTPError [AbortError]: The user aborted a request. at RequestHandler.execute (/rbd/pnpm-volume/92ce8857-84ba-4805-80ae-d024d200051d/node_modules/.registry.npmjs.org/discord.js/12.0.2/node_modules/discord.js/src/rest/RequestHandler.js:107:21) at processTicksAndRejections (internal/process/task_queues.js:88:5) { name: 'AbortError', code: 500, method: 'put', path: '/channels/693713772862504990/permissions/688564329850994720' } spammed in console full error log: errorlog.txt

menix1337 commented 4 years ago

im having the same issue while using the mute command on my bot i have error HTTPError [AbortError]: The user aborted a request. at RequestHandler.execute (/rbd/pnpm-volume/92ce8857-84ba-4805-80ae-d024d200051d/node_modules/.registry.npmjs.org/discord.js/12.0.2/node_modules/discord.js/src/rest/RequestHandler.js:107:21) at processTicksAndRejections (internal/process/task_queues.js:88:5) { name: 'AbortError', code: 500, method: 'put', path: '/channels/693713772862504990/permissions/688564329850994720' } spammed in console full error log: errorlog.txt

The exact same here

ghost commented 4 years ago

Yea sometimes a file upload fails

Upload speed is 3mbps, would a faster internet connection prevent these issues?

ghost commented 4 years ago

If discord.js is timing out uploads after 15s, well an 8mb file will take longer than that to upload with 3mbps. I think the request handler should only time out after the upload progress stops changing, if that is possible.

netgfx commented 4 years ago

I'm seeing this:

HTTPError [AbortError]: The user aborted a request.
    at RequestHandler.execute (C:\xampp\htdocs\AlbionAssets\node_modules\discord.js\src\rest\RequestHandler.js:107:21)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:85:5) {
  name: 'AbortError',
  code: 500,
  method: 'post',
  path: '/channels/704607063799627830/messages'
}

when I try to attach two image-files (discord URLs) in an embed like this:

const messageEmbed = new Discord.MessageEmbed().setTitle("Title").attachFiles(imagesResult).setTimestamp().setFooter('Made by Netgfx');

Passing 1 file resolves correctly and the message is send.

LeManock commented 4 years ago

I have had this problem for 2 weeks. Any solution please?

fjeddy commented 4 years ago

This is a problem that suddenly occured out of the blue for me two days ago, right now about 2% of all messages come through, the remaining 99% fails with an AbortError. No sudden changes, just suddenly started to fail the majority.

For some reason, I get messages that are sent many many hours before at the same time as I get messages sent right now, which is super weird, as they come up even after a node reboot has been performed, makes me think the issue is on Discords side, seems like it's getting all my requests but not actually handling them all.

iCrawl commented 4 years ago

Is this hosted somewhere or running on your computer/home-network?

fjeddy commented 4 years ago

@iCrawl It's hosted on the home network, in terms of Discord, does that matter?

Saamstep commented 4 years ago

Hey there! Same thing happening to me as well on a home network.AbortError: The user aborted a request.. Happens when I try to log in as the bot user. Node 12.18.1 LTS Djs 12.2.0 Ubuntu 20.04 LTS

I tried restarting my home network just for the sake of it but that didn't help. Little server machine is connected via Ethernet.

Funny thing is that I have an old raspberry pi running a couple bots (djs v11 and node v10 so quite old lol) and that is running 100% fine.

Tried catching errors on the login method but no additional errors other than the one above were logged.

Edit: Potential Solution Restarting the host machine got me to start my bot back up. May work for others (:

ghost commented 4 years ago

ratelimits.

fjeddy commented 4 years ago

@mihabozic123 No, that can't be it, unless it's something brand new from Discord.

This bot has been running two months straight from my home network, without any issues. The amount of messages sent hasn't changed and the volume stays pretty much the same.

Rate limiting is also handled by the discordjs library, as well as Discord, as far as I know, then Discord only really punishes you if you ignore the rate limits in the header and keep sending requests that fails. Which discordjs handles. I also notice in my bot that the messages have around a 40 second delay when it's going at it's heaviest, this is the rate limit kicking in, where the messages arrive faster then discordjs is able to send them, this is completely normal.

What happened now, suddenly, out of the blue, 5-6-7 days ago, was that some messages came through, then suddenly, the next 300 messages where ignored, just, gone, until a new batch of messages arrived and only a few popped up, the rest vanished. Except, hours later, the messages that vanished, suddenly pops up in-between new messages.

Now, the problem seems to be gone, I'm no longer losing messages. BUT, messages that where lost 5-6-7 days ago, still seems to popup inbetween new messages once in a while. It's just weird.

Note I don't think this is DiscordJS's faulth, some times external apps send so many messages that I don't really need, that I just end up restarting the discord bot after the external apps are done to wipe the queue and just ignore the messages they sent. During this i restarted the bot multiple times, to avoid having a bunch of messages coming back later, just clear the queue, but seems like DiscordJS is actually sending the messages correctly to discord, but it's discord that's messing something up, and is not sending the messages as it should to the channels.

TKDBB84 commented 4 years ago

I can second that this likely is not rate limiting, my bot is hosted on a remote VPS that has near 99.99% uptime, and my bot has extremely minimal traffic, my bot maybe sends at most a few message per hour to discord: and I also received this error today. It could see it relating to generally long response time, or issues with routing. (i don't think it's anything wrong in discordjs)

ghost commented 4 years ago

@fjeddy well in my case it was ratelimits (on multiple bots, same error because of ratelimits)

GRA0007 commented 4 years ago

I was getting this error while trying to change the server icon using an animated gif from a bot, it was timing out because it was taking longer than 15 seconds to upload the image. I solved this by increasing the restRequestTimeout in the client options, but perhaps this is an issue that should be resolved so that changing a server icon doesn't time out if the upload is still in progress.

fjeddy commented 4 years ago

That's sort of the point @GRA0007, if the request is hanging it times out, instead of hanging forever. The limit has to be something, and it seems they chose 15 seconds.

If the upload times out, it's usually because something is wrong and the file is not actually uploading (Not as it should).

GRA0007 commented 4 years ago

@fjeddy Yeah, my point was to check if the progress of the file upload is still increasing, and if it is, reset the timeout. That way the request won't timeout if the file is still actually uploading. In any case, changing the timeout for now was enough to fix my problem, but it's only a temporary solution.

DreamXZE commented 4 years ago

The problem isn't the timeout time, which has to be something. Sometimes the request hangout forever without reason (even like for sending/editing a message). The problem is more that, like mention here or in the d.js discord server, the retryLimit got no effect, and actually, on this error, there is no retry at all, but it should be include regarding the error code. The only way to get around that it's to make your own retry module on all event that contact the discord server (send/editing message, fetching member etc etc etc).

fjeddy commented 4 years ago

There is no errors, thats why it times out. If the Discord servers responded anything, anything at all, the request wouldn't hang and eventually kill itself. The problem in this specific scenario, is most likely just that, slow connections / servers / poor code that's causing requests to take longer then they should before they respond.

DreamXZE commented 4 years ago

Well, when even the staff/support tell that can happen randomly without reason, no, there is no specific relation with connections/servers/poor code. It can if it happens a lot, but it can also randomly hit you. If sending a message randomly timeout without specific reason, you can easely monitoring your connection to check. But again, that's not the debate.

The client option have a retryLimit, which is How many times to retry on 5XX errors. The timeout error got the error code 500, and is never retried by the code itself. Which is a problem that was never fixed, and is the purpose of my initial post/discovery (the 1st October message).

ghost commented 4 years ago

couldn't it check the upload progress and only time out if it stops changing?

fjeddy commented 4 years ago

That what happens, no response, no updates. So it times out to avoid stalling.

Ayfri commented 4 years ago

I'm getting this error when trying to remove a reaction to a message like this :

const waitEmoji = client.emojis.resolve('638831506126536718');
// [...]
await message.reactions.cache.find(reaction => reaction.emoji === waitEmoji).users.remove(client.user.id);
cwkhawand commented 4 years ago

Same here, bots won't even connect to the Gateway, and if they do, they'll crash a couple of minutes later with the AbortError. The funny thing is that on my local computer it works fine, but on the VPS it doesn't. Network is stable and fast (20ms ping and 100 Mbps up/down) so I don't think it's a network issue on my end. It really seems to happen randomly, but this is the first time it hits so hard (previously it used to hit, but with way less errors).

Update: I turned off all interactions with the Discord Gateway (Discord Bots, Webhooks, etc...) for a couple of hours (around 2 hours) and the error has vanished. Maybe Discord is rate limiting (?) us somehow?

sabattle commented 4 years ago

I'm also getting an AbortError, but only when hosting on my local network. I can recreate it consistently by not interacting with the bot for 10 minutes and then attempting to use a command. The first command sent will timeout with an AbortError after a couple seconds, and all others used during that time will all send at once. My bot does not have this issue on my production server.

jmalexan commented 4 years ago

I have a bot that sends out a message at a certain time each week to specific channels on servers that choose to subscribe. The bot overall is perfectly capable of responding to commands at all times, but when it comes to sending these weekly messages it can only get through a portion of them before the rest fail due to AbortErrors.

I've tried restarting the server and the script. The only solution that ended up working for me this week is to build in a retry mechanism myself. The script will try to send the message in each server up to 10 times. All messages went through after 3 attempts (each one having more messages go through).

To me this seems to point pretty directly to a rate limiting issue on my end, given that the error only occurs when messages are being sent on mass. I thought the library was supposed to handle rate limiting? Am I simply incorrectly configuring a client option?

neofutur commented 4 years ago

I m also hitting this error with my discord bot ( https://github.com/neofutur/heatmapbot )

is there any recommended fix or workaround found since September 2019 ?

kyranet commented 4 years ago

There's literally a PR opened that fixes this. Or rather, will make this be nearly impossible to hit again unless your VPS's internet dies completely for longer than 30 seconds.

sahhas16 commented 3 years ago

Same problem,any fixes?

kyranet commented 3 years ago

Same problem,any fixes?

Increase retryLimit, from the docs.

Miha1T commented 3 years ago

I'm seeing this:

root@elabor:~/ElaMail# node app
/root/ElaMail/node_modules/discord.js/src/rest/RequestHandler.js:93
        throw new HTTPError(error.message, error.constructor.name, error.status, request.method, request.path);
              ^

HTTPError [AbortError]: The user aborted a request.
    at RequestHandler.execute (/root/ElaMail/node_modules/discord.js/src/rest/RequestHandler.js:93:15)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async RequestHandler.push (/root/ElaMail/node_modules/discord.js/src/rest/RequestHandler.js:39:14)
    at async WebSocketManager.connect (/root/ElaMail/node_modules/discord.js/src/client/websocket/WebSocketManager.js:138:9)
    at async Client.login (/root/ElaMail/node_modules/discord.js/src/client/Client.js:223:7) {
  code: 500,
  method: 'get',
  path: '/gateway/bot'
}

What could you do to solve the problem faster

kyranet commented 3 years ago

Check whether or not you're sending payloads too long for your network, if you aren't, then it might be either issues in your end or (less likely) in Discord's end.

You can also increase restRequestTimeout, by default is 15 seconds, which is far more than enough for the vast majority of requests.

Miha1T commented 3 years ago

and how I do it

kyranet commented 3 years ago

It's restRequestTimeout in ClientOptions, please move to the support server for further queries.