Skip to main content

Rate Limiting

Rate Limiting Algorithm#

To prevent DDoS attacks to Spire API and handle load gracefully we implemented query rate limiting using Leaky Bucket Algorithm algorithm. Each request that goes to api.spire.com/graphql is being rate limited according to the available quota:

  • If the quota is not yet exceeded, then the response will be returned as soon as it's processed by the Spire API without any limitations.
  • If the quota was already exceeded, the processing of the request will be delayed. When request finally got procesed the client will receive response alongside with the TOO_MANY_REQUESTS error.
  • Quota gains back as soon as time goes according to moving time window.
  • If the request is waiting for too long in the rate limiter queue it will timeout eventually. In this case client will receive empty response alongside with the TIMEOUT_ERROR error.

The current request quota is up to 60 requests per minute per token.

We expect our custoemrs wont be affected by the rate limiter unless they are doing a lot of paralled requests with the same token. If you are querying spire API sequentially then you likely won't be affected by the rate limiter at all.

Rate Limiter Info#

To provide you transparent feedback about rate limiter, each response that passed rate limiter will contain requestQuota field in the response extensions with data about the remaining quota:

{
"data": { ... },
"extensions": {
"requestQuota": {
"limit": "60 req/m (burst 60)",
"remaining": 59
}
}
}

Where:

  • limit - textual description of current rate limiter policy.
  • remaining - number of requests per minute left for current quota. Reaching 0 indicates the query was rate-limited.

This information allows clients to adjust the request rate before making the next request.

Rate Limiting Multi Root Queries#

Requests with multi-root queries are treated as several independent requests from the rate limiter perspective. Each root query executed in parallel and represented independent self-sufficient request to our underlying infrastructure.

For example, the following query will be counted as 2 standalone queries:

{
tankers: vessels(shipType: [TANKER_CRUDE, TANKER_PRODUCT, TANKER_CHEMICALS]) {
nodes {
staticData {
mmsi
name
}
}
}
cargo: vessels(shipType: [CONTAINER, GENERAL_CARGO]) {
nodes {
staticData {
mmsi
name
}
}
}
}

The rate limiter quota will be decreased by 2 and will look in the following way:

{
"data": {
"tankers": { ... },
"cargo": { ... }
},
"extensions": {
"requestQuota": {
"limit": "60 req/m (burst 60)",
"remaining": 58
}
}
}