View Source Nostrum.Api.Ratelimiter (Nostrum v0.8.0)
Handles REST calls to the Discord API while respecting ratelimits.
purpose
Purpose
Discord's API returns information about ratelimits that we must respect. This module performs serialization of these requests through a single process, thus preventing concurrency issues from arising if two processes make a remote API call at the same time.
inner-workings
Inner workings
When a client process wants to perform some request on the Discord API, it
sends a request to the GenServer
behind this module to ask it to :queue
the incoming request.
The server looks up the ratelimit buckets for the given endpoint using the
configured Nostrum.Store.RatelimitBucket
. If no bucket is available, a
request will be sent out directly, and the server will wait for the response.
After receiving a response, the ratelimiter updates the matching ratelimit bucket and return the response to the client.
If the client disconnects from the ratelimiter, or the request is dropped by the ratelimiter for another reason - usually a timeout - while the request is still existing on Discord's end, the Ratelimiter will log the response later when it receives it.
serialization-and-buckets
Serialization and buckets
We serialize all REST requests in nostrum through this process to prevent
concurrency issues arising from multiple clients exhausting the bucket (e.g.
going to a Nostrum.Store.RatelimitBucket.remaining/0
value below 0
).
This critical spot only needs to happen shortly before running the request,
but only if we already have a bucket for the coming request. If we do not
have a bucket already, we must serialize it and not make further requests for
the same bucket until we have received information from Discord on the
ratelimits on the given endpoint. Otherwise, we may end up running multiple
requests to the same endpoint because no bucket was stored to tell us that we
shouldn't. A more efficient alternative may be only blocking requests to the
specific bucket we have sent a request to by keeping track of "unbucketed
running requests" and removing elements as we retrieve bucket information.
Link to this section Summary
Types
Return values of start functions.
Functions
Returns a specification to start this module under a supervisor.
Retrieves a proper ratelimit endpoint from a given route and url.
Callback implementation for GenServer.init/1
.
Queue the given request.
Starts the ratelimiter.
Link to this section Types
Return values of start functions.
Link to this section Functions
Returns a specification to start this module under a supervisor.
See Supervisor
.
Retrieves a proper ratelimit endpoint from a given route and url.
Callback implementation for GenServer.init/1
.
Queue the given request.
If the ratelimiter tells us to sit it out and we have more than 0
attempts
remaining, we sleep out the given retry time and ask it to queue again
afterwards.
@spec start_link([]) :: on_start()
Starts the ratelimiter.