-
Notifications
You must be signed in to change notification settings - Fork 232
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2da2183
commit bfc174d
Showing
1 changed file
with
135 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,148 @@ | ||
**Rate-limiting pattern** | ||
Here's an extended version of the documentation with usage examples for all the rules (FixedWindow, Timespan, And, and Or): | ||
|
||
Rate limiting involves restricting the number of requests that a client can make. | ||
A client is identified with an access token, which is used for every request to a resource. | ||
To prevent abuse of the server, APIs enforce rate-limiting techniques. | ||
The rate-limiting application can decide whether to allow the request based on the client. | ||
The client makes an API call to a particular resource; the server checks whether the request for this client is within the limit. | ||
If the request is within the limit, then the request goes through. | ||
Otherwise, the API call is restricted. | ||
--- | ||
|
||
Some examples of request-limiting rules (you could imagine any others) | ||
* X requests per timespan; | ||
* a certain timespan has passed since the last call; | ||
* For US-based tokens, we use X requests per timespan; for EU-based tokens, a certain timespan has passed since the last call. | ||
# Rate Limiter Library Documentation | ||
|
||
The goal is to design a class(-es) that manages each API resource's rate limits by a set of provided *configurable and extendable* rules. For example, for one resource, you could configure the limiter to use Rule A; for another one - Rule B; for a third one - both A + B, etc. Any combination of rules should be possible; keep this fact in mind when designing the classes. | ||
## Overview | ||
|
||
We're more interested in the design itself than in some intelligent and tricky rate-limiting algorithm. There is no need to use a database (in-memory storage is fine) or any web framework. Do not waste time on preparing complex environment, reusable class library covered by a set of tests is more than enough. | ||
The `RateLimiter` library provides a flexible and extensible way to control the rate of requests for specific identifiers, such as IP addresses or tokens. The library supports several rules for rate limiting, including fixed windows, timespan-based limits, and composite rules (AND, OR). This allows for the application of complex rate-limiting strategies to prevent abuse and ensure fairness. | ||
|
||
There is a Test Project set up for you to use. However, you are welcome to create your own test project and use whatever test runner you like. | ||
The library consists of several components: | ||
1. **Identifiers** – Represent the entities whose rate of requests is being limited (e.g., IP address, token). | ||
2. **Rules** – Define the conditions under which requests are allowed or denied, including `FixedWindow`, `Timespan`, and logical combinations like `And` and `Or`. | ||
3. **History** – Keeps track of requests and allows checking whether a request exceeds the limits within a specific timeframe. | ||
|
||
You are welcome to ask any questions regarding the requirements—treat us as product owners, analysts, or whoever knows the business. | ||
If you have any questions or concerns, please submit them as a [GitHub issue](https://github.com/crexi-dev/rate-limiter/issues). | ||
--- | ||
|
||
You should [fork](https://help.github.com/en/github/getting-started-with-github/fork-a-repo) the project and [create a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request-from-a-fork) named as `FirstName LastName` once you are finished. | ||
## Key Components | ||
|
||
Good luck! | ||
### 1. **Identifiers** | ||
|
||
An identifier is an entity whose rate is being limited. For example, you can limit the number of requests per IP address or token. | ||
|
||
|
||
--- | ||
|
||
### 2. **Rules** | ||
|
||
Rules define the conditions for limiting requests. | ||
|
||
#### Fixed Window Rule (`FixedWindow`) | ||
|
||
This rule limits the number of requests that can be made within a fixed window of time (e.g., 10 requests per 60 seconds). | ||
|
||
##### Usage Example: Fixed Window Rule | ||
|
||
```csharp | ||
var history = new InMemoryFixedWindowHistory(); | ||
var fixedWindowRule = new FixedWindow(history, maxCount: 5, window: 10); // Max 5 requests in 10 seconds | ||
var ipAddress = new IpAddress("192.168.1.1"); | ||
|
||
for (int i = 0; i < 6; i++) | ||
{ | ||
bool isAllowed = fixedWindowRule.Check(ipAddress); | ||
Console.WriteLine(isAllowed ? "Request allowed" : "Request denied"); | ||
|
||
// Simulate a delay between requests | ||
Task.Delay(1000).Wait(); // 1 second delay | ||
} | ||
``` | ||
|
||
--- | ||
|
||
#### Timespan Rule (`Timespan`) | ||
|
||
This rule checks the time passed since the last request for an identifier. It allows a request only if a specified timespan has passed since the last request. | ||
|
||
|
||
##### Usage Example: Timespan Rule | ||
|
||
```csharp | ||
var history = new InMemoryTimespanHistory(); | ||
var timespanRule = new Timespan(history, timespan: 5); // Allow one request every 5 seconds | ||
var token = new Token("abcdef12345"); | ||
|
||
for (int i = 0; i < 6; i++) | ||
{ | ||
bool isAllowed = timespanRule.Check(token); | ||
Console.WriteLine(isAllowed ? "Request allowed" : "Request denied"); | ||
|
||
// Simulate a delay between requests | ||
Task.Delay(2000).Wait(); // 2 second delay | ||
} | ||
``` | ||
|
||
--- | ||
|
||
#### Logical Rules (`And`, `Or`) | ||
|
||
You can combine multiple rules using `And` (all rules must pass) or `Or` (any rule must pass). | ||
|
||
##### `And` Rule | ||
|
||
This rule checks if all the given rules pass. | ||
|
||
|
||
##### Usage Example: `And` Rule | ||
|
||
```csharp | ||
var fixedWindowHistory = new InMemoryFixedWindowHistory(); | ||
var timespanHistory = new InMemoryTimespanHistory(); | ||
|
||
var fixedWindowRule = new FixedWindow(fixedWindowHistory, maxCount: 3, window: 10); | ||
var timespanRule = new Timespan(timespanHistory, timespan: 5); | ||
|
||
var andRule = new And(new IRule[] { fixedWindowRule, timespanRule }); | ||
|
||
var ipAddress = new IpAddress("192.168.1.1"); | ||
|
||
for (int i = 0; i < 5; i++) | ||
{ | ||
bool isAllowed = andRule.Check(ipAddress); | ||
Console.WriteLine(isAllowed ? "Request allowed" : "Request denied"); | ||
|
||
// Simulate a delay between requests | ||
Task.Delay(1000).Wait(); // 1 second delay | ||
} | ||
``` | ||
|
||
--- | ||
|
||
##### `Or` Rule | ||
|
||
This rule checks if any of the given rules pass. | ||
|
||
|
||
##### Usage Example: `Or` Rule | ||
|
||
```csharp | ||
var fixedWindowHistory = new InMemoryFixedWindowHistory(); | ||
var timespanHistory = new InMemoryTimespanHistory(); | ||
|
||
var fixedWindowRule = new FixedWindow(fixedWindowHistory, maxCount: 2, window: 5); // Max 2 requests in 5 seconds | ||
var timespanRule = new Timespan(timespanHistory, timespan: 10); // Allow one request every 10 seconds | ||
var orRule = new Or(new IRule[] { fixedWindowRule, timespanRule }); | ||
|
||
var ipAddress = new IpAddress("192.168.1.1"); | ||
|
||
for (int i = 0; i < 5; i++) | ||
{ | ||
bool isAllowed = orRule.Check(ipAddress); | ||
Console.WriteLine(isAllowed ? "Request allowed" : "Request denied"); | ||
|
||
// Simulate a delay between requests | ||
Task.Delay(1000).Wait(); // 1 second delay | ||
} | ||
``` | ||
|
||
--- | ||
|
||
## Conclusion | ||
|
||
The `RateLimiter` library is a powerful tool for controlling request rates based on different conditions. By combining various rules (such as `FixedWindow`, `Timespan`, and logical combinations like `And` and `Or`), you can build sophisticated rate-limiting strategies tailored to your application’s needs. | ||
|
||
This flexibility makes it easy to protect your application from abuse while ensuring fair access for legitimate users. |