You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A rate limiting plugin for [ServiceStack](https://servicestack.net/) that uses [Redis](http://redis.io/) for calculating and persisting request counts.
2
6
3
-
# Requirements
7
+
##Requirements
4
8
5
9
An accessible running Redis instance.
6
10
7
11
The plugin needs to be passed an IRedisClientsManager instance to work.
8
12
9
-
# Quick Start
13
+
## Quick Start
14
+
15
+
Install the package [https://www.nuget.org/packages/ServiceStack.RateLimit.Redis](https://www.nuget.org/packages/ServiceStack.RateLimit.Redis/)
16
+
```bash
17
+
PM> Install-Package ServiceStack.RateLimit.Redis
18
+
```
10
19
11
20
Add the following to your `AppHost.Configure` method to register the plugin:
12
21
13
22
```csharp
14
23
publicoverridevoidConfigure(Containercontainer)
15
24
{
16
-
// Default ServiceStack config
17
-
SetConfig(newHostConfig
18
-
{
19
-
WebHostUrl="http://api.acme.com",
20
-
ApiVersion="2.0"
21
-
});
22
-
23
-
// Register Redis client manager using locally running Redis instance
@@ -40,7 +41,7 @@ To override this add an AppSetting with key *lmt:default* to the App.Config/Web.
40
41
41
42
The lookup keys for more granular control are specified below.
42
43
43
-
## Demo
44
+
###Demo
44
45
45
46
The included DemoService is a self hosted AppHost listening on port 8090 with Resource and User limits.
46
47
@@ -49,13 +50,14 @@ Basic authentication is used for identifying users. There are 3 users: Cheetara,
49
50
The "Postman Samples" folder contains a sample [Postman](https://www.getpostman.com/) collection containing a few calls including authorisation setup.
50
51
51
52
52
-
# Overview
53
+
##Overview
53
54
The plugin registers a [global request filter](https://github.com/ServiceStack/ServiceStack/wiki/Request-and-response-filters#global-request-filters). Every time a request is received a check is made using a [Redis LUA script](http://redis.io/commands/eval). If the specified limits have not been hit then the request is processed as expected. However, if the limit has been reached then a [429](https://tools.ietf.org/html/rfc6585#page-3) "Too Many Requests" response is generated and processing of the request is halted.
54
55
55
56
Two possible headers are returned from any endpoint that is protecte: x-ratelimit-request and x-ratelimit-user. They will show the seconds duration, the limit and how many remaining calls are available per request, or user respectively.
56
57
57
-
## Rate Limits
58
-
At a high level, rate limits can be set at either User or Resource level (by default a resource in this instance is the DTO type name). Limits are fetched from [IAppSettings](https://github.com/ServiceStack/ServiceStack/wiki/AppSettings) and can be set at the following levels, in order of precedence:
58
+
### Rate Limits
59
+
60
+
At a high level, rate limits can be set at either **User** or **Resource** level (by default a resource in this instance is the DTO type name). Limits are fetched from [IAppSettings](https://github.com/ServiceStack/ServiceStack/wiki/AppSettings) and can be set at the following levels, in order of precedence:
59
61
60
62
* User for resource - User 123 can make X requests to a specific resource (e.g. /api/products). (config key: "lmt:{resourceName}:{userId}")
61
63
* User - User 123 can make X total requests for specific time period(s). (config key: "lmt:usr:{userId}")
@@ -65,13 +67,13 @@ At a high level, rate limits can be set at either User or Resource level (by def
65
67
66
68
User limits AND resource limits will be calculated at the same time (if present). User limits are calculated first. If a limit is hit subsequent wider limits are not incremented (e.g. if limit per second is hit, limit per minute would not be counted).
67
69
68
-
### Limit Representation
70
+
####Limit Representation
69
71
All limits are per second and are stored as a LimitGroup object serialised to JSV. For example, the following shows a limit of 5 requests per second, 15 per minute (60s) and 100 per hour (3600s):
A LUA script is used for doing the heavy lifting and keeping track of limit totals. To save bandwith on calls to Redis the [EVALSHA](http://redis.io/commands/evalsha) command is used to call a LUA script which has previously been [loaded](http://redis.io/commands/script-load).
76
78
77
79
The default implementation of ILimitProvider (see below) will check IAppSettings for a value with key "script:ratelimit". This value will be the SHA1 of the script to use. Using this method means that the script can be managed external to the plugin.
@@ -80,7 +82,7 @@ If an AppSetting is not found with the specified key then the RateLimitHash.lua
80
82
81
83
**Note:** The RateLimitHash.lua script does not currently use a sliding expiry, instead is resets every X seconds. E.g. if the limit is for 50 requests in 3600 seconds (1 hour) then 50 requests could be made at 10:59 and then 50 request can be made at 11:01. This is something that may be looked at in the future.
82
84
83
-
## Extensibility
85
+
###Extensibility
84
86
There are a few extension point that can be set when adding the plugin:
85
87
86
88
* CorrelationIdExtractor - This is a delegate function that customises how an individual request is identified. By default it uses the value of HTTP Header with name specified by CorrelationIdHeader property. **Note:** This is primarily required for when a ServiceStack service calls subsequent ServiceStack services that all use this plugin as it will avoid user totals being incremented multiple times for the same request.
Since user limits are available a user **must** be authenticated or the request will return a 401: Forbidden response. This is a default behaviour and can be changed by overriding the `LimitKeyGenerator.GetConsumerId(request)` method.
107
+
108
+
The script needs to be updated to take a list of all Redis Keys that will be operated on. This is documented in the [Redis EVAL documentation](http://redis.io/commands/EVAL) and is particularly relevant if running a Redis Cluster.
This plugin works well with a shared configuration model where rate limits can be centrally managed globally or across multiple instances of your servicestack instances. The rate limiting scripts can also be updated centrally to make adjustments at runtime.
114
+
115
+
## Attributions
103
116
104
-
Since user limits are available a user **must** be authenticated or the request will return a 401: Forbidden response. This is a default behaviour and can be changed by overriding the `LimitKeyGenerator.GetConsumerId(request)` method.
117
+
*http://www.corytaylor.ca/api-throttling-with-servicestack/by Cory Taylor
0 commit comments