Rate Limiting
Rate Limiting
Section titled “Rate Limiting”Rate limit communication and handling
Overview
Section titled “Overview”Rate limiting protects services from overload. Mesh provides standardized mechanisms for:
- Proactive visibility — Clients see usage before hitting limits
- Clear errors — Structured error when limits are exceeded
- Recovery guidance — Explicit retry timing
Rate Limit Metadata
Section titled “Rate Limit Metadata”Servers SHOULD include rate limit information in response meta for every request:
{ "meta": { "duration": { "value": 127, "unit": "millisecond" }, "rate_limit": { "limit": 1000, "used": 153, "remaining": 847, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 45, "unit": "second" } } }}Fields
Section titled “Fields”| Field | Type | Required | Description |
|---|---|---|---|
limit | integer | Yes | Maximum requests allowed in the window |
used | integer | Yes | Requests used in current window |
remaining | integer | Yes | Requests remaining in current window |
window | object | Yes | Time window duration (value/unit) |
resets_in | object | Yes | Time until window resets (value/unit) |
Rate Limit Error
Section titled “Rate Limit Error”When a client exceeds the rate limit:
{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_123", "result": null, "errors": [{ "code": "RATE_LIMITED", "message": "Rate limit exceeded", "retryable": true, "details": { "limit": 1000, "used": 1000, "window": { "value": 1, "unit": "minute" }, "retry_after": { "value": 45, "unit": "second" } } }], "meta": { "rate_limit": { "limit": 1000, "used": 1000, "remaining": 0, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 45, "unit": "second" } } }}Error Details
Section titled “Error Details”| Field | Type | Description |
|---|---|---|
limit | integer | Maximum requests allowed |
used | integer | Requests used (equal to limit when exceeded) |
window | object | Time window duration |
retry_after | object | Recommended wait before retrying |
Rate Limit Scopes
Section titled “Rate Limit Scopes”Rate limits MAY apply at different scopes:
| Scope | Description |
|---|---|
global | Across all clients |
service | Per calling service |
function | Per function |
user | Per authenticated user |
When multiple scopes apply, include all in metadata:
{ "meta": { "rate_limits": { "global": { "limit": 10000, "used": 4523, "remaining": 5477, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 32, "unit": "second" } }, "service": { "limit": 1000, "used": 847, "remaining": 153, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 32, "unit": "second" } } } }}Client Behavior
Section titled “Client Behavior”Proactive Throttling
Section titled “Proactive Throttling”Clients SHOULD monitor meta.rate_limit.remaining and throttle requests before hitting limits:
if (remaining < threshold) { delay = calculate_backoff(remaining, resets_in) wait(delay)}Handling RateLimited
Section titled “Handling RateLimited”When receiving RATE_LIMITED error:
- Extract
retry_afterfrom error details - Wait the specified duration
- Retry with exponential backoff if still limited
- Set maximum retry attempts
Clients MUST NOT retry immediately without waiting.
Backoff Strategy
Section titled “Backoff Strategy”Recommended exponential backoff:
wait_time = min(retry_after * (2 ^ attempt), max_wait)Where:
retry_after— From error detailsattempt— Retry attempt number (0, 1, 2, …)max_wait— Maximum wait time (e.g., 5 minutes)
Server Implementation
Section titled “Server Implementation”Rate Limit Algorithms
Section titled “Rate Limit Algorithms”Common algorithms:
| Algorithm | Description |
|---|---|
| Fixed Window | Reset counter at fixed intervals |
| Sliding Window | Rolling time window |
| Token Bucket | Tokens replenish over time |
| Leaky Bucket | Requests drain at constant rate |
Response Requirements
Section titled “Response Requirements”Servers implementing rate limiting MUST:
- Return
RATE_LIMITEDerror when limit exceeded - Include
retry_afterin error details - Set
retryable: trueon the error
Servers SHOULD:
- Include
rate_limitinmetaon every response - Use consistent window boundaries across requests
- Document rate limit policies
Graceful Degradation
Section titled “Graceful Degradation”Servers MAY implement soft limits:
{ "meta": { "rate_limit": { "limit": 1000, "used": 950, "remaining": 50, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 15, "unit": "second" }, "warning": "Approaching rate limit" } }}Discovery
Section titled “Discovery”Clients can discover rate limit policies via system functions:
// Request{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_limits", "call": { "function": "mesh.capabilities", "version": "1", "arguments": {} }}
// Response{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_limits", "result": { "service": "orders-api", "limits": { "rate_limits": [ { "scope": "service", "limit": 1000, "window": { "value": 1, "unit": "minute" } }, { "scope": "function", "function": "orders.create", "limit": 100, "window": { "value": 1, "unit": "minute" } } ] } }}Examples
Section titled “Examples”Normal Response with Rate Limit Info
Section titled “Normal Response with Rate Limit Info”{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_123", "result": { "order_id": 456, "status": "created" }, "meta": { "duration": { "value": 89, "unit": "millisecond" }, "rate_limit": { "limit": 1000, "used": 42, "remaining": 958, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 47, "unit": "second" } } }}Approaching Limit
Section titled “Approaching Limit”{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_456", "result": { "success": true }, "meta": { "duration": { "value": 34, "unit": "millisecond" }, "rate_limit": { "limit": 1000, "used": 985, "remaining": 15, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 12, "unit": "second" }, "warning": "Rate limit nearly exhausted" } }}Rate Limited
Section titled “Rate Limited”{ "protocol": { "name": "mesh", "version": "0.1.0" }, "id": "req_789", "result": null, "errors": [{ "code": "RATE_LIMITED", "message": "Rate limit exceeded for orders.create", "retryable": true, "details": { "limit": 100, "used": 100, "window": { "value": 1, "unit": "minute" }, "retry_after": { "value": 23, "unit": "second" }, "scope": "function", "function": "orders.create" } }], "meta": { "rate_limit": { "limit": 100, "used": 100, "remaining": 0, "window": { "value": 1, "unit": "minute" }, "resets_in": { "value": 23, "unit": "second" } } }}