Feature: X-Ratelimit-Bucket Support
Created by: Neuheit
Summary
Fixes #456 (closed)
Details
This PR implements support for the X-Ratelimit-Bucket header, which will improve ratelimit handling. This does so by allowing buckets to be grouped via returned response hashes so the rest client can handle shared ratelimits, as the current implementation does not handle shared buckets correctly.
The concurrent bucket cache has been replaced with 2 concurrent caches: one that holds an index of methods + routes (hash-key)
to hashes
, and the other holding bucket ids (hash + major params) to ratelimit buckets. The first request made creates an unlimited version of the hash (see xml docs), which will create an unlimited bucket id attached to a newly created bucket (unlimited referring to non-existent ratelimits). When the hash is received through headers, the unlimited hash and buckeId are replaced with the updated hash values (see xml docs for more indepth examples).
Unfortunately, due to a bug on Discord's end, the hash will only be updated once on our end. The reasoning is because the delete message route constantly switches between 2 bucket hashes: 5/5, and 3/1, the 5/5 being shared with post messages and edited messages. If there are constant requests occurring between the 2 buckets, this will cause many ratelimits to be hit if the hashes frequently update. This has the drawback of not recognizing updated hashes on existing buckets if Discord decides to update their API, in which case users would need to Dispose their clients to reobtain the correct hashes.
Additionally, I implemented a bucket cleaner which compares the current time to the ratelimit's reset date, and if it is past a certain time, automatically removes it from the bucket cache for every minute. I feel this will be a beneficial change to larger bots that create a large number of buckets. This will not clean any buckets that are being processed by the rest client (which is what the RequestQueue dictionary is for).
Changes proposed
- Implements support for the new bucket header
- Added support for a bucket cleaner which runs every minute
- Added a dispose method for the rest client to properly remove all buckets.
- Added a few null checks for when the Discord client is disposed.