Rate Limiting and Resilience
By the Syncfusion DevTutorials team · Last updated
Protect your API from too much traffic with rate limits and 429 Too Many Requests, and make clients cope with slow or failing services using retries and backoff.
Rate limiting controls how many requests a caller can make within a period of time.
Resilience helps applications continue working when services are slow, overloaded, or temporarily unavailable. Instead of failing immediately, a resilient client waits, retries carefully, and avoids making a bad situation worse. Together, rate limiting and resilience protect both the API and its users.
Watch One Client Flood the API
A partner application contains a bug. Instead of loading the menu once, it repeatedly calls GET /menu in a loop. Press Run.
Program.cs — no limit at all
Results:
- All six requests receive
200 OK. /statsreports:{"requests": 6}
Nothing slows the client down. Nothing protects the API. A small bug may generate thousands or millions of requests. This can increase costs, slow responses, overload servers, and affect other customers.
In simple words: the API needs rules that prevent one caller from using unlimited resources.
TL;DR
- A rate limit restricts how many requests a caller may make during a time period.
- Going over the limit should return
429 Too Many Requests. - Include the
Retry-Afterheader, to tell the client when it may try again. - Apply limits per user, API key, or client.
- Fixed windows are simple but can be bursty.
- Token buckets handle bursts more smoothly.
- Retry temporary failures using exponential backoff and jitter.
- Never retry
400 Bad Request, and never retry non-idempotent POST operations without an Idempotency-Key.
A Real-World Example
Imagine a shop selling a limited-edition product. A sign at the entrance says: One per customer.
The goal is fairness. Without the rule, one person buys everything, and everyone else gets nothing. Rate limiting serves the same purpose. It ensures fair usage, stable performance, and protection from bugs and abuse.
Requests are counted within a time window. Requests over the limit receive 429 Too Many Requests and a Retry-After value.
What You Will Learn
In this lesson, you will learn:
- Why APIs use rate limits.
- How fixed-window rate limiting works.
- How to limit requests per API key.
- How token bucket rate limiting handles bursts.
- How resilient clients retry safely.
- When retries should and should not happen.
A Fixed Window Rate Limit
A fixed-window limiter counts requests during a fixed period. Example rule: 3 requests every 60 seconds. The first three requests succeed. The fourth request exceeds the limit.
Program.cs — fixed window limit
Requests Within the Limit
At 10s, 20s and 30s, the responses are 200 OK. The remaining requests decrease: 2, 1, 0.
Request Over the Limit
At 40s, the response is 429 Too Many Requests with Retry-After: 20. The client must wait until the 60-second window ends.
New Window
At 61s, the counter resets. Requests are allowed again, and the response is 200 OK.
A 429 Too Many Requests response is normal behavior. Well-behaved clients read the Retry-After header, pause their requests, and try again later.
Rate Limits Per API Key
Rate limits should apply to each caller separately. The activity of one user should not affect the access of another user.
Program.cs — a limit per API key
Example:
Asha's Key
The limit is 3 requests. The results are 200, 200, 200, 429. The response includes Retry-After: 52.
Swiggo's Key
It uses a completely separate counter. Even after Asha reaches her limit, 200 OK still succeeds for Swiggo.
Missing Key
The API cannot identify the caller, so the response is 401 Unauthorized. Without an identity, limits cannot be enforced properly.
Token Bucket Rate Limiting
Fixed windows have a weakness. A caller could send 3 requests at second 59 and 3 requests at second 60, and effectively make six requests almost at once.
A token bucket gives smoother behavior.
How It Works
The bucket stores tokens. Example: Capacity: 3 tokens and Refill: 1 token per second
Each request uses one token. No token means no request.
TokenBucket.cs — bursts and refill
Example:
Second 0
The bucket has 3 tokens. The results are ✓ ✓ ✓ ✗.
Second 1
One token returns. The result is ✓.
Second 2
One more token returns. The results are ✓ ✗ ✗.
Second 6
The bucket has refilled completely. Another burst is allowed.
Token buckets allow occasional bursts while they enforce a long-term rate.
Resilience and Retries
Sometimes requests fail because of temporary problems, such as network issues, timeouts, service restarts, and short outages. Retrying immediately can make the situation worse. Instead, clients should retry gradually.
Exponential Backoff
Wait longer after each failure. Example: Attempt 1 → wait 100ms, Attempt 2 → wait 200ms, Attempt 3 → wait 400ms
The delay doubles each time.
Jitter
Add a small random delay. Example: 107ms, 223ms, 412ms
This prevents thousands of clients from retrying at the same moment.
Retry delays grow after each failure. Jitter spreads retries across time to prevent spikes.
Retry.cs — backoff and Retry-After
Example:
Timeout
Attempt 1 ends with Timeout, and the client waits 107ms. Attempt 2 ends with Timeout, and the client waits 223ms. Attempt 3 returns 200 OK, which is a success.
Retry-After
If the server returns 429 Too Many Requests with Retry-After: 2, the client waits 2000ms.
The instruction of the server takes priority over the calculated backoff delay.
Circuit Breakers
Sometimes retries are not enough. A service may stay unavailable for a long time. Continuing to send requests only creates more load.
A circuit breaker stops requests for a while.
Typical behavior:
- Several failures occur.
- The circuit opens.
- Requests fail immediately.
- After a waiting period, one test request is allowed.
- If it succeeds, normal traffic resumes.
The benefits are that it protects struggling services, reduces unnecessary traffic, and recovers more quickly after outages.
When You Should Not Retry
Some failures will never succeed if they are retried.
Do Not Retry Validation Errors
Example: 400 Bad Request
The request itself is invalid. Repeating it produces the same result.
Be Careful with POST Requests
Consider POST /payments. The payment may have succeeded even if the response was lost. A blind retry may charge the customer twice.
Only retry POST requests when they use an Idempotency-Key, which makes sure that duplicate requests are handled safely.
Never retry a payment or a similar operation unless the request is idempotent. Retries should be safe, predictable, and controlled.
Rate Limiting in ASP.NET Core
Real ASP.NET Core applications include built-in rate limiting support. Common limiter types include Fixed Window, Sliding Window, and Token Bucket.
Rate limits can be partitioned by API key, user, IP address, or custom identifiers. Applications can also configure 429 responses, retry information, and different limits for different endpoints.
How to Choose a Limit
Rate limits should be based on real usage patterns. Example: if normal users make 20 requests per minute, then 100 requests per minute might be a reasonable limit.
Limits that are too strict frustrate legitimate users. Limits that are too high give little protection. Monitor usage before you decide.
Set limits using real production data, not guesses. Review traffic patterns regularly, and change the limits when necessary.
Where You See This
- Public APIs return
429 Too Many Requestswhen limits are exceeded. - Login systems limit failed sign-in attempts.
- Mobile apps retry temporary network failures.
- Cloud SDKs use backoff and jitter automatically.
- Payment APIs rely on idempotency keys for safe retries.
Common mistakes
| Symptom | Cause | Fix |
|---|---|---|
| One client slows the API for everyone | No rate limiting | Add limits per user or API key |
Clients keep receiving 429 repeatedly | Retry-After is ignored | Wait the specified amount of time |
| Customers are charged twice | POST requests are retried unsafely | Use Idempotency-Key or avoid retries |
| Outages become worse under load | Clients retry immediately | Use backoff, jitter, and circuit breakers |
| Invalid requests are retried repeatedly | 400 responses are treated as temporary failures | Retry only transient failures such as 429, 503, or timeouts |
| Legitimate users are blocked too often | Limits are too low | Review real usage and adjust limits |
Exercises
What to Remember
- A rate limit stops one caller from taking everything. Count per key.
- When a caller is over the limit, send
429 Too Many RequestswithRetry-Afterand a Problem Details body. - A fixed window is simple. A token bucket allows short bursts and fills up slowly again.
- Clients retry temporary failures with exponential backoff and jitter. They also obey
Retry-After. - Never retry a
400, and never retry a POST without an Idempotency-Key.
Next: API Monitoring and Logging. You will learn how to watch your API in production, so that you see the floods, the 429s and the slow calls before your customers do.