Rate Limiting for Stellar Horizon

Learn how not to burst over the available dynamic limit in a period of time for Stellar Horizon.

Stellar Horizon users may encounter rate limits from time to time. These limits are designed intelligently to allow for bursts of access rather than enforcing a strict quota or average distribution over time.

As of November 2022, the default rate limit for dedicated node customers is 15,000 requests/hour. Contact Support if you need to raise the limit.

📘

Info:

Please note that Horizon's rate limiting algorithm follows the GCRA rate limit.

Maintain Visibility with Headers

You can maintain visibility on your available quota for the current period. If you adjust your request velocity based on the returned header values, you can ensure you never exhaust your rate limit.

Blockdaemon passes through headers without alteration as defined in the official Stellar documentation on rate limiting.

  • X-RateLimit-Limit – The Stellar documentation refers to this as “The maximum number of requests that the current client can make in one hour.” However, observation indicates this is the limit of calls in a given “window”. We can observe this in practice by paying attention to the header return values.
  • X-RateLimit-Remaining – The Stellar documentation refers to this as “The number of remaining requests for the current window.” This is accurate for observed use. This is the most important number to watch, indicating how many calls you may make until you encounter a rate limit.
  • X-RateLimit-Reset – The Stellar documentation refers to this as “Seconds until a new window starts.” This is also accurate for observed use. If you wanted to wait for a full call quota, you would like to delay by the window this indicates. However, the quota is dynamic and more easily understood as a cooldown rather than a hard lockout.

If you exceed your rate limit — X-RateLimit-Remaining reaches 0 — you will receive an HTTP 429 response code and the additional header retry-after, specifying a value in seconds that you should delay further requests.

Understanding Limits in Practice

In practice, the rate limit acts like a leaky bucket that slowly drains when water isn’t added to it. Every request you make adds water to the bucket. If you add water faster than the bucket drains, you will overfill the bucket and hit your rate limit.

If you make 50 requests and wait three seconds before your next request, you will see the X-RateLimit-Remaining counter increase and the X-RateLimit-Reset decrease. Therefore, if you use enough requests in a time period to reach 0 remaining, you don’t need to wait for the full duration until a Reset.


This is easily understood from a terminal window.

In a terminal window, enter the following command:

curl -I MY_BLOCKDAEMON_NODE_ADDRESS/fee_stats?auth=MY_AUTH_TOKEN

Where MY_BLOCKDAEMON_NODE_ADDRESS is the node address given to you on the node card, and MY_AUTH_TOKEN is everything after “auth=” in your node address.

You will get a response that looks something like this:

server: nginx/1.18.0
date: Thu, 20 Aug 2020 20:53:01 GMT
cache-control: no-cache, no-store, max-age=0
vary: Origin
x-ratelimit-limit: 101
x-ratelimit-remaining: 100
x-ratelimit-reset: 2
access-control-allow-origin: *

If you run the command several times in rapid succession, you will see the remaining count decrease and the reset period increase, as below:

server: nginx/1.18.0
date: Thu, 20 Aug 2020 20:18:31 GMT
cache-control: no-cache, no-store, max-age=0
vary: Origin
x-ratelimit-limit: 101
x-ratelimit-remaining: 99
x-ratelimit-reset: 4
access-control-allow-origin: *
server: nginx/1.18.0
date: Thu, 20 Aug 2020 20:18:31 GMT
cache-control: no-cache, no-store, max-age=0
vary: Origin
x-ratelimit-limit: 101
x-ratelimit-remaining: 98
x-ratelimit-reset: 5
access-control-allow-origin: *

Similarly, if you wait a few seconds, the reset period will refresh to 0, and you will have a full quota again.

If you want to understand it interactively with a shell script, you can run this on his local machine:

#!/bin/bashcounter=1
while [ $counter -le 150 ]
do
curl -I <a class="c-link" href="https://my_blockdaemon_node_address/fee_stats?auth=MY_AUTH_TOKEN" target="_blank" rel="noopener noreferrer">https://MY_BLOCKDAEMON_NODE_ADDRESS/fee_stats?auth=MY_AUTH_TOKEN</a>
((counter++))
done

Conclusion

Stellar Horizon rate limits are dynamic and do not consist of a simple quota or a naive division of available calls across the time period. By reading and implementing response headers into your code, you can ensure you don’t burst over the available dynamic limit in a period.


Useful Resources

👋 Need Help?

Contact us through email or our support page for any issues, bugs, or assistance you may need.