Skip to content

Commit 9c10c93

Browse files
Scott MackayScott Mackay
authored andcommitted
Merge pull request #3 in SS/servicestack.ratelimit.redis from develop to master
* commit '29a692955b13af601d908f185581e0c392dfb9be': Added attributions to Readme Update readme.md Update readme.md
2 parents df83296 + 29a6929 commit 9c10c93

File tree

1 file changed

+34
-21
lines changed

1 file changed

+34
-21
lines changed

readme.md

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
1+
# ServiceStack.RateLimit.Redis
2+
[![Build status](https://ci.appveyor.com/api/projects/status/3m3pl4fqwjnoyp48/branch/master?svg=true)](https://ci.appveyor.com/project/wwwlicious/servicestack-ratelimit-redis/branch/master)
3+
[![NuGet version](https://badge.fury.io/nu/servicestack.ratelimit.redis.svg)](https://badge.fury.io/nu/servicestack.ratelimit.redis)
4+
15
A rate limiting plugin for [ServiceStack](https://servicestack.net/) that uses [Redis](http://redis.io/) for calculating and persisting request counts.
26

3-
# Requirements
7+
## Requirements
48

59
An accessible running Redis instance.
610

711
The plugin needs to be passed an IRedisClientsManager instance to work.
812

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+
```
1019

1120
Add the following to your `AppHost.Configure` method to register the plugin:
1221

1322
```csharp
1423
public override void Configure(Container container)
1524
{
16-
// Default ServiceStack config
17-
SetConfig(new HostConfig
18-
{
19-
WebHostUrl = "http://api.acme.com",
20-
ApiVersion = "2.0"
21-
});
22-
23-
// Register Redis client manager using locally running Redis instance
24-
var redisConnection = "127.0.0.1:6379"
25-
Container.Register<IRedisClientsManager>(new BasicRedisClientManager(redisConnection));
25+
// Register Redis client manager using locally running Redis instance
26+
Container.Register<IRedisClientsManager>(new BasicRedisClientManager("127.0.0.1:6379"));
2627

2728
// Register plugin. Every service is now rate limited!
2829
Plugins.Add(new RateLimitFeature(Container.Resolve<IRedisClientsManager>()));
@@ -40,7 +41,7 @@ To override this add an AppSetting with key *lmt:default* to the App.Config/Web.
4041

4142
The lookup keys for more granular control are specified below.
4243

43-
## Demo
44+
### Demo
4445

4546
The included DemoService is a self hosted AppHost listening on port 8090 with Resource and User limits.
4647

@@ -49,13 +50,14 @@ Basic authentication is used for identifying users. There are 3 users: Cheetara,
4950
The "Postman Samples" folder contains a sample [Postman](https://www.getpostman.com/) collection containing a few calls including authorisation setup.
5051

5152

52-
# Overview
53+
## Overview
5354
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.
5455

5556
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.
5657

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:
5961

6062
* User for resource - User 123 can make X requests to a specific resource (e.g. /api/products). (config key: "lmt:{resourceName}:{userId}")
6163
* 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
6567

6668
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).
6769

68-
### Limit Representation
70+
#### Limit Representation
6971
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):
7072
```xml
7173
{Limits:[{Limit:5,Seconds:1},{Limit:15,Seconds:60},{Limit:100,Seconds:3600}]}
7274
```
7375

74-
### LUA Script
76+
#### LUA Script
7577
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).
7678

7779
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
8082

8183
**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.
8284

83-
## Extensibility
85+
### Extensibility
8486
There are a few extension point that can be set when adding the plugin:
8587

8688
* 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.
@@ -99,6 +101,17 @@ Plugins.Add(new RateLimitFeature(Container.Resolve<IRedisClientsManager>())
99101
});
100102
```
101103

102-
## Caveats
104+
### Caveats
105+
106+
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.
109+
110+
### Extras
111+
112+
* [ServiceStack.Configuration.Consul](https://github.com/MacLeanElectrical/servicestack-configuration-consul) -
113+
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
103116

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

Comments
 (0)