Trying to get member/roles without being rate limited
I have a bot that is in ~20k servers and it does some work to role-gate certain features in our application based on server membership & roles. Recently we've had a bit of an explosion of users and we are having some major issues with being cloudflare/IP rate limited when trying to do this behavior.
So a couple of q's
1) Is there any way to know if we've been IP rate limited with discord.js? Currently the server just hangs and does nothing when this happens. I could only tell that's what's happening when I restart and get a 429 error when the shards are initializing.
2) Is there any way to cache ALL of the membership data for ALL of the servers we're in, so we don't have to frequently request user membership data from the server? I am using
makeCache: Options.cacheEverything()
but that doesn't seem to do the trick. It would be awesome to just cache all that data in memory and let the websocket update the cache instead of having to fetch it constantly...
We do store & cache results in our DB, and use the bot events to try and keep that cache fresh but we still frequently need to check the server.
I feel like there's something I'm missing here, and I'm not dying to refactor things to do rest calls and rotate proxies (I had assumed the normal websocket client would be better than rest calls because of the data caching)... Also wtf I can't even log into discord.com when I get my local IP limited 😅
Any help is greatly appreciated.
[email protected]
[email protected]
26 Replies
- What's your exact discord.js
npm list discord.js
and node node -v
version?
- Not a discord.js issue? Check out #other-js-ts.
- Consider reading #how-to-get-help to improve your question!
- Explain what exactly your issue is.
- Post the full error stack trace, not just the top part!
- Show your code!
- Issue solved? Press the button!Also I gotta say - IP rate limiting has gotta be the stupidest thing about discord (and seemingly completely undocumented :pepefacepalm: )
We were hosting on render.com but those servers use shared outbound IPs (and of course it's hard to do a proxy with a websocket client) -- one of our competitors realized this and ran a bot on render.com with the express intention of triggering the IP rate limit and breaking our bot.
Awesome.
20k servers on shared hosting is already pretty wild
You should really be looking for dedicated instances at that scale
So - it's a dedicated instance, but all of the instances in the same region on render.com use the same outbound ip
To address the original issue though regarding caching / role data etc, can you help me understand what it is that's role gated, and why you wouldn't have the data incoming with whatever event is firing a role-gated function?
Why does it need to be pre-cached?
I mean, that was just an idea to not have to fetch it constantly, if it were all in the cache already
My question is more why is it being fetched at all
What is being restricted?
So basically it's raffle software, and the owner of a discord server would use it to gate the ability to enter a raffle based on a role for example
So this raffle is just for those with the more advanced role or w/e
Yep, got it. So whats the method for someone to enter the raffle? Slash command, button?
Any of those sort of interactions would include full member data, no fetching required
The bot can send an embed with a button, yeah - we also have a website ppl can enter on
Most ppl use the website these days
The website would be the problem then I assume
Yeah
Its possible to get full member data using a single gateway call,
guild.members.fetch()
Then that should be generally kept up to date by eventsRight, yeah that's what we do. Unfortunately it's like 80-90% of ppl's data isn't already cached 😦
Lots of distinct user/server combos
From what I can tell that's the call that gets cloudflare rate limited, and then it just hangs
Its not even an API call though, its web socket payloads
I assume you have the GuildMembers intent
Yeah
Hm - would it be better to do a rest call (if that's even possible)?
No
ah ok
guild.members.fetch("user id")
is an API call that would spam and hit rate limits
guild.members.fetch()
receives packets over the websocket, specifically intended to fetch all membersohhhh interesting
If you do it 20k times on boot yeah its going to be problematic but a sensible interval and backoff should be fine?
You'll just consume a shitload of RAM
yeah I can live with the RAM consumption I think
Hmmmm that gives me an idea tho
Is there an issue with the fetch call if there are a lot of members?
Or any limits on that?
I didn't realize there was a distinction between passing a userId or not
I think there's at least a couple of servers we're in that have the higher tier of members
Yeah huge distinction
Hm -- trying this out I am getting the "Members didn't arrive in time" error a bunch
Are you sure you have the intent?
Are you hitting multiple guilds at once?
May have been hitting multiple at once, yeah
I put the call into a queue class I have built to make sure it's one at a time and it seems to be doing better
Hmm so I have this working...
However it will just randomly "reconnect" shards and then (i think) it has to re-cache everything again
Or at least it triggers the shard ready event (which is where I start pulling down all the data...)