Skip to content

concurrency_limit ​

concurrency_limit bounds the number of requests handled at the same time. Requests over the limit wait in a queue or get 503 Service Unavailable.

Unlike rate_limit, which counts requests per time window, it protects slow endpoints and upstreams from too much parallel work.

yaml
server:
  http:
    middlewares:
      export_limit:
        concurrency_limit:
          max: 4
          queue: 20
          queue_timeout: 30s
      tenant_limit:
        concurrency_limit:
          max: 10
          key:
            - header:X-Tenant-Id
FieldDefaultDescription
maxRequired. Requests handled at the same time per key.
queue0Requests per key waiting for a slot. 0 rejects requests over max right away.
queue_timeout10sLongest wait in the queue before the request is rejected.
keyParts to limit by, combined. Without it one limit applies to all requests.
trusted_proxiesCIDRs whose forwarding headers are used for the ip key.
status_code503Status of rejected requests, e.g. 429.

Rejected requests get Retry-After: 1. Queued requests get a slot in arrival order. A client that disconnects while waiting leaves the queue.

Keys ​

key accepts the same parts as rate_limit: ip, realip, path, host, method, header:<name>, query:<name> and cookie:<name>. A part missing in the request falls back to the client IP so leaving out a header does not escape the limit.

The limit is kept in memory per Turna instance and per named middleware.

Long-lived requests such as WebSockets and SSE hold a slot until they end. Leave them out of the route or give them their own limit.