Global rate limits and throttling in Discourse


(Sam Saffron) #1

Discourse ships with 3 different global rate limits that can be configured by site admins.

Global per-ip rate limits

These limits apply to every unique IP address that hits the Discourse application. (files that are served directly from the filesystem or the CDN are excluded)

By default this rate limit is disabled, but we are considering enabling it out of the box.

DISCOURSE_MAX_REQS_PER_IP_MODE : default none, this rate limit does not apply out of the box yet. (other options are warn and warn+block)

DISCOURSE_MAX_REQS_PER_IP_PER_MINUTE: number of requests per IP per minute (default is 200)

DISCOURSE_MAX_REQS_PER_IP_PER_10_SECONDS: number of requests per IP per 10 seconds (default is 50)

DISCOURSE_MAX_ASSET_REQS_PER_IP_PER_10_SECONDS: number of asset (avatars/css) requests per IP per 10 seconds (default is 200)

DISCOURSE_MAX_REQS_RATE_LIMIT_ON_PRIVATE: should the rate limit apply to private IPs accessing Discourse? default is false.

User API rate limits

The mobile applications acquire a user API key per device to access Discourse on behalf of a user (using an open protocol). These API keys are very tightly limited.

DISCOURSE_MAX_USER_API_REQS_PER_MINUTE: default 20
DISCOURSE_MAX_USER_API_REQS_PER_DAY: default 2880

Admin API rate limits

The administrative API keys can be generated via the yoursite.com/admin/api/keys page. These keys can operate on behalf of users, but require administrative privileges to generate. They are limited, but not as strictly as the user API keys.

DISCOURSE_MAX_ADMIN_API_REQS_PER_KEY_PER_MINUTE : 60

Versions of Discourse prior to 1.9 did not include this limiting.

What should I do if I hit a rate limit and get throttled?

If you are consuming the API programmatically and receive back a 429 status code throttle reply you should respect it and slow down.

As an end user you should not really experience rate limits if you do, slow down. You could trigger it by opening 50 tabs real quick or doing something like that.

How do I amend these limits?

To amend the limits add the desired change into your app.yml file in the env section.

If you are hosted by Discourse contact team@discourse.org


Troubleshooting a 429 (rate limit)
Changing/removing API rate limit with category creation
Is there a limit of API requests?
Rate limit while creating new users and adding them to groups
Few clarifications on Discourse
Internal links not oneboxing in private messages
Enable user to Generate API key
#2

Just curious as to what the conversations were that made this a consideration… any specific examples or patterns that you’ve seen emerge from existing customers?


(Joshua Rosenfeld) #3

In general we believe that everything should be rate limited: Rate Limiting and Velocity Checking. The reason that global per-ip rate limits were added was because users were finding creative ways around the existing rate limits.

For example, opening a very large number of tabs all at once creates a huge number of concurrent requests to the server. If global rate limiting is disabled your server will be hit by all those requests at once. Limiting this to a reasonable number allows you to open many tabs still, but not too many that your server has to start queueing the requests.


(Karl) #4

Hi Sam,
I have a couple of usability queries around the data returned from the API.

When I looked at the data returned from the API a couple of weeks ago, the back of period only appears to be accessible via the text which explains why the limiting is in place.

{"errors":["We have a daily limit on how many times that action can be
taken. Please wait 10 seconds before trying
again."],"error_type":"rate_limit"}

Is it possible to add a second error class (perhaps retry_delay or similar) which contains the number of seconds to back off as a separate field?

My second comment relates to the error pasted above - is it possible that ‘we have a daily limit’ is being used incorrectly, if I only need to wait another 10 seconds before I can try again? I’m guessing it should say “there is a limit on usage per X number seconds”.

thanks,
kk


(Sam Saffron) #5

Fixed …

And … fixed


(Karl) #6

Like lightning, thanks Sam!

I will try and test it in the next couple of days and see how I go.


(Sam Saffron) #7

OK, will get it deployed a bit later today.


(DiscourseMetrics.com) #8

Will it be possible to change this value from the admin panel? If these strict values are enabled by default and can not easily be changed by site admins, I fear I’ll have to do a really, really costly rewrite of the DiscourseMetrics backend.


(Sam Saffron) #9

no, sadly this is not planned, these settings are meant to be hard to amend. For hosting scenarios such as our hosting we are in control of this and not our customers.


(Karl) #10

Hi Sam,
Another query regarding the limits.

Is there an API endpoint we can query to proactively determine how many requests are permitted in a period of time?


(Blake Erickson) #11

There is not an API endpoint to check for number of requests left. The best method right now is to check the http status code for a 429 and then back off for the amount listed in the body of that response.


(Karl) #12

Hi Blake,

I was imaging something more proactive, for example:

  • I need to send 80 queries
  • I know i’m limited to something less than that
  • query to api.discourse/something
    -> oh, I can do 40 queries per minute
    -> better space my queries out over 2 minutes

Since there is nothing in that vein, I will simply rely on the 429 :slight_smile:
karl.


(Karl) #13

Hi again,
I just spotted this response to a 429:

“You have performed this action too many times. Please wait 0 seconds before trying again.”

It smacks of off-by-one error somewhere - if it isn’t its a bit of an odd response.


(Joshua Rosenfeld) #14

My guess is it’s a rounding error (please wait 0.4 seconds), but Sam would need to confirm.


(Sam Saffron) #15

I think its more likely a rounding error. Will have a look at improving it so we pretend 1 if it is 0.1.


(Sam Saffron) #16

2 posts were split to a new topic: When rate limiting is hit return return a Retry-After header


#17

Is there any way to change this setting? In app.yml maybe?