API Reference#
|
Rate limiting with commonly used storage backends |
|
Rate limiting strategies |
|
Implementations of storage backends to be used with |
|
Asynchronous rate limiting strategies |
|
Implementations of storage backends to be used with |
Strategies#
The available built in rate limiting strategies which expect
a single parameter: a subclass of Storage
.
Provided by limits.strategies
- class FixedWindowRateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
Reference: Fixed Window
- test(item: RateLimitItem, *identifiers: str) bool [source]#
Check if the rate limit can be consumed
- class FixedWindowElasticExpiryRateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
Reference: Fixed Window with Elastic Expiry
- class MovingWindowRateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
Reference: Moving Window
- test(item: RateLimitItem, *identifiers: str) bool [source]#
Check if the rate limit can be consumed
All strategies implement the same abstract base class:
- class RateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
- abstract hit(item: RateLimitItem, *identifiers: str, cost: int = 1) bool [source]#
Consume the rate limit
- abstract test(item: RateLimitItem, *identifiers: str) bool [source]#
Check the rate limit without consuming from it.
These variants should be used in for asyncio support. These strategies
expose async variants and expect a subclass of limits.aio.storage.Storage
Provided by limits.aio.strategies
- class FixedWindowRateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
Reference: Fixed Window
- async hit(item: RateLimitItem, *identifiers: str, cost: int = 1) bool [source]#
Consume the rate limit
- async test(item: RateLimitItem, *identifiers: str) bool [source]#
Check if the rate limit can be consumed
- class FixedWindowElasticExpiryRateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
Reference: Fixed Window with Elastic Expiry
- async hit(item: RateLimitItem, *identifiers: str, cost: int = 1) bool [source]#
Consume the rate limit
- Parameters
item¶ – a
limits.limits.RateLimitItem
instanceidentifiers¶ – variable list of strings to uniquely identify the limit
cost¶ – The cost of this hit, default 1
- class MovingWindowRateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
Reference: Moving Window
- async hit(item: RateLimitItem, *identifiers: str, cost: int = 1) bool [source]#
Consume the rate limit
- async test(item: RateLimitItem, *identifiers: str) bool [source]#
Check if the rate limit can be consumed
All strategies implement the same abstract base class:
- class RateLimiter(storage: Union[Storage, limits.aio.storage.Storage])[source]#
- abstract async hit(item: RateLimitItem, *identifiers: str, cost: int = 1) bool [source]#
Consume the rate limit
- abstract async test(item: RateLimitItem, *identifiers: str) bool [source]#
Check if the rate limit can be consumed
Storage#
Storage Factory function#
Provided by limits.storage
- storage_from_string(storage_string: str, **options: Union[float, str, bool]) Union[Storage, Storage] [source]#
Factory function to get an instance of the storage class based on the uri of the storage. In most cases using it should be sufficient instead of directly instantiating the storage classes. for example:
from limits.storage import storage_from_string memory = from_string("memory://") memcached = from_string("memcached://localhost:11211") redis = from_string("redis://localhost:6379")
The same function can be used to construct the Async Storage variants, for example:
from limits.storage import storage_from_string memory = storage_from_string("async+memory://") memcached = storage_from_string("async+memcached://localhost:11211") redis = storage_from_string("asycn+redis://localhost:6379")
- Parameters
storage_string¶ – a string of the form
scheme://host:port
. More details about supported storage schemes can be found at Storage schemeoptions¶ – all remaining keyword arguments are passed to the constructor matched by
storage_string
.
- Raises
ConfigurationError – when the
storage_string
cannot be mapped to a registeredlimits.storage.Storage
orlimits.aio.storage.Storage
instance.
Synchronous Storage#
Provided by limits.storage
In-Memory#
- class MemoryStorage(uri: Optional[str] = None, **_: str)[source]#
rate limit storage using
collections.Counter
as an in memory storage for fixed and elastic window strategies, and a simple list to implement moving window strategy.- incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
- get_num_acquired(key: str, expiry: int) int [source]#
returns the number of entries already acquired
Redis#
- class RedisStorage(uri: str, connection_pool: Optional[redis.connection.ConnectionPool] = None, **options: Union[float, str, bool])[source]#
Rate limit storage with redis as backend.
Depends on redis.
- Parameters
uri¶ – uri of the form
redis://[:password]@host:port
,redis://[:password]@host:port/db
,rediss://[:password]@host:port
,redis+unix:///path/to/sock
etc. This uri is passed directly toredis.from_url()
except for the case ofredis+unix://
where it is replaced withunix://
.connection_pool¶ – if provided, the redis client is initialized with the connection pool and any other params passed as
options
options¶ – all remaining keyword arguments are passed directly to the constructor of
redis.Redis
- Raises
ConfigurationError – when the redis library is not available
- STORAGE_SCHEME: Optional[List[str]] = ['redis', 'rediss', 'redis+unix']#
The storage scheme for redis
- incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
Redis Cluster#
- class RedisClusterStorage(uri: str, **options: Union[float, str, bool])[source]#
Rate limit storage with redis cluster as backend
Depends on redis.
Changed in version 2.5.0: Cluster support was provided by the redis-py-cluster library which has been absorbed into the official redis client. By default the
redis.cluster.RedisCluster
client will be used however if the version of the package is lower than4.2.0
the implementation will fallback to trying to userediscluster.RedisCluster
.- Parameters
uri¶ – url of the form
redis+cluster://[:password]@host:port,host:port
options¶ – all remaining keyword arguments are passed directly to the constructor of
redis.cluster.RedisCluster
- Raises
ConfigurationError – when the redis library is not available or if the redis cluster cannot be reached.
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {'max_connections': 1000}#
Default options passed to the
RedisCluster
- get_moving_window(key: str, limit: int, expiry: int) Tuple[int, int] #
returns the starting point and the number of entries in the moving window
- incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int #
increments the counter for a given rate limit key
- reset() Optional[int] [source]#
Redis Clusters are sharded and deleting across shards can’t be done atomically. Because of this, this reset loops over all keys that are prefixed with ‘LIMITER’ and calls delete on them, one at a time.
Warning
This operation was not tested with extremely large data sets. On a large production based system, care should be taken with its usage as it could be slow on very large data sets
Redis Sentinel#
- class RedisSentinelStorage(uri: str, service_name: Optional[str] = None, use_replicas: bool = True, sentinel_kwargs: Optional[Dict[str, Union[float, str, bool]]] = None, **options: Union[float, str, bool])[source]#
Rate limit storage with redis sentinel as backend
Depends on redis package
- Parameters
uri¶ – url of the form
redis+sentinel://host:port,host:port/service_name
service_name¶ – sentinel service name (if not provided in
uri
)use_replicas¶ – Whether to use replicas for read only operations
sentinel_kwargs¶ – kwargs to pass as
sentinel_kwargs
toredis.sentinel.Sentinel
options¶ – all remaining keyword arguments are passed directly to the constructor of
redis.sentinel.Sentinel
- Raises
ConfigurationError – when the redis library is not available or if the redis master host cannot be pinged.
- STORAGE_SCHEME: Optional[List[str]] = ['redis+sentinel']#
The storage scheme for redis accessed via a redis sentinel installation
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {'socket_timeout': 0.2}#
Default options passed to
Sentinel
- get_moving_window(key: str, limit: int, expiry: int) Tuple[int, int] #
returns the starting point and the number of entries in the moving window
- incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int #
increments the counter for a given rate limit key
Memcached#
- class MemcachedStorage(uri: str, **options: Union[str, Callable[[], MemcachedClientP]])[source]#
Rate limit storage with memcached as backend.
Depends on pymemcache.
- Parameters
uri¶ – memcached location of the form
memcached://host:port,host:port
,memcached:///var/tmp/path/to/sock
options¶ – all remaining keyword arguments are passed directly to the constructor of
pymemcache.client.base.PooledClient
orpymemcache.client.hash.HashClient
(if there are more than one hosts specified)
- Raises
ConfigurationError – when pymemcache is not available
- get_client(module: module, hosts: List[Tuple[str, int]], **kwargs: str) MemcachedClientP [source]#
returns a memcached client.
- property storage: limits.typing.MemcachedClientP#
lazily creates a memcached client instance using a thread local
- incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
MongoDB#
- class MongoDBStorage(uri: str, database_name: str = 'limits', **options: Union[int, str, bool])[source]#
Rate limit storage with MongoDB as backend.
Depends on pymongo.
New in version 2.1.
- Parameters
uri¶ – uri of the form
mongodb://[user:password]@host:port?...
, This uri is passed directly toMongoClient
database_name¶ – The database to use for storing the rate limit collections.
options¶ – all remaining keyword arguments are merged with
DEFAULT_OPTIONS
and passed to the constructor ofMongoClient
- Raises
ConfigurationError – when the pymongo library is not available
- DEFAULT_OPTIONS: Dict[str, Union[int, str, bool]] = {'connectTimeoutMS': 1000, 'serverSelectionTimeoutMS': 1000, 'socketTimeoutMS': 1000}#
Default options passed to
MongoClient
- reset() Optional[int] [source]#
Delete all rate limit keys in the rate limit collections (counters, windows)
- incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
- check() bool [source]#
Check if storage is healthy by calling
pymongo.mongo_client.MongoClient.server_info()
Async Storage#
Provided by limits.aio.storage
In-Memory#
- class MemoryStorage(uri: Optional[str] = None, **_: str)[source]#
rate limit storage using
collections.Counter
as an in memory storage for fixed and elastic window strategies, and a simple list to implement moving window strategy.New in version 2.1.
- STORAGE_SCHEME: Optional[List[str]] = ['async+memory']#
The storage scheme for in process memory storage for use in an async context
- async incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
- async get_num_acquired(key: str, expiry: int) int [source]#
returns the number of entries already acquired
Redis#
- class RedisStorage(uri: str, connection_pool: Optional[coredis.ConnectionPool] = None, **options: Union[float, str, bool])[source]#
Rate limit storage with redis as backend.
Depends on coredis
New in version 2.1.
- Parameters
uri¶ –
uri of the form:
async+redis://[:password]@host:port
async+redis://[:password]@host:port/db
async+rediss://[:password]@host:port
async+unix:///path/to/sock
etc…
This uri is passed directly to
coredis.Redis.from_url()
with the initialasync
removed, except for the case ofasync+redis+unix
where it is replaced withunix
.connection_pool¶ – if provided, the redis client is initialized with the connection pool and any other params passed as
options
options¶ – all remaining keyword arguments are passed directly to the constructor of
coredis.Redis
- Raises
ConfigurationError – when the redis library is not available
- STORAGE_SCHEME: Optional[List[str]] = ['async+redis', 'async+rediss', 'async+redis+unix']#
The storage schemes for redis to be used in an async context
- async incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
- async check() bool [source]#
Check if storage is healthy by calling
coredis.Redis.ping()
- async reset() Optional[int] [source]#
This function calls a Lua Script to delete keys prefixed with ‘LIMITER’ in block of 5000.
Warning
This operation was designed to be fast, but was not tested on a large production based system. Be careful with its usage as it could be slow on very large data sets.
Redis Cluster#
- class RedisClusterStorage(uri: str, **options: Union[float, str, bool])[source]#
Rate limit storage with redis cluster as backend
Depends on coredis
New in version 2.1.
- Parameters
uri¶ – url of the form
async+redis+cluster://[:password]@host:port,host:port
options¶ – all remaining keyword arguments are passed directly to the constructor of
coredis.RedisCluster
- Raises
ConfigurationError – when the coredis library is not available or if the redis host cannot be pinged.
- STORAGE_SCHEME: Optional[List[str]] = ['async+redis+cluster']#
The storage schemes for redis cluster to be used in an async context
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {'max_connections': 1000}#
Default options passed to
coredis.RedisCluster
- async reset() Optional[int] [source]#
Redis Clusters are sharded and deleting across shards can’t be done atomically. Because of this, this reset loops over all keys that are prefixed with ‘LIMITER’ and calls delete on them, one at a time.
Warning
This operation was not tested with extremely large data sets. On a large production based system, care should be taken with its usage as it could be slow on very large data sets
- async check() bool #
Check if storage is healthy by calling
coredis.Redis.ping()
Redis Sentinel#
- class RedisSentinelStorage(uri: str, service_name: Optional[str] = None, use_replicas: bool = True, sentinel_kwargs: Optional[Dict[str, Union[float, str, bool]]] = None, **options: Union[float, str, bool])[source]#
Rate limit storage with redis sentinel as backend
Depends on coredis
New in version 2.1.
- Parameters
uri¶ – url of the form
async+redis+sentinel://host:port,host:port/service_name
optional¶ (sentinel_kwargs,) – sentinel service name (if not provided in uri)
use_replicas¶ – Whether to use replicas for read only operations
optional¶ – kwargs to pass as
sentinel_kwargs
tocoredis.sentinel.Sentinel
options¶ – all remaining keyword arguments are passed directly to the constructor of
coredis.sentinel.Sentinel
- Raises
ConfigurationError – when the coredis library is not available or if the redis primary host cannot be pinged.
- STORAGE_SCHEME: Optional[List[str]] = ['async+redis+sentinel']#
The storage scheme for redis accessed via a redis sentinel installation
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {'stream_timeout': 0.2}#
Default options passed to
Sentinel
- async get_moving_window(key: str, limit: int, expiry: int) Tuple[int, int] #
returns the starting point and the number of entries in the moving window
- async incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int #
increments the counter for a given rate limit key
Memcached#
- class MemcachedStorage(uri: str, **options: Union[float, str, bool])[source]#
Rate limit storage with memcached as backend.
Depends on emcache
New in version 2.1.
- Parameters
- Raises
ConfigurationError – when emcache is not available
- STORAGE_SCHEME: Optional[List[str]] = ['async+memcached']#
The storage scheme for memcached to be used in an async context
- async incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
MongoDB#
- class MongoDBStorage(uri: str, database_name: str = 'limits', **options: Union[float, str, bool])[source]#
Rate limit storage with MongoDB as backend.
Depends on motor
New in version 2.1.
- Parameters
uri¶ – uri of the form
async+mongodb://[user:password]@host:port?...
, This uri is passed directly toAsyncIOMotorClient
database_name¶ – The database to use for storing the rate limit collections.
options¶ – all remaining keyword arguments are merged with
DEFAULT_OPTIONS
and passed to the constructor ofAsyncIOMotorClient
- Raises
ConfigurationError – when the motor or pymongo are not available
- STORAGE_SCHEME: Optional[List[str]] = ['async+mongodb', 'async+mongodb+srv']#
The storage scheme for MongoDB for use in an async context
- DEFAULT_OPTIONS: Dict[str, Union[float, str, bool]] = {'connectTimeoutMS': 1000, 'serverSelectionTimeoutMS': 1000, 'socketTimeoutMS': 1000}#
Default options passed to
AsyncIOMotorClient
- async reset() Optional[int] [source]#
Delete all rate limit keys in the rate limit collections (counters, windows)
- async incr(key: str, expiry: int, elastic_expiry: bool = False, amount: int = 1) int [source]#
increments the counter for a given rate limit key
- async check() bool [source]#
Check if storage is healthy by calling
motor.motor_asyncio.AsyncIOMotorClient.server_info()
Abstract storage classes#
- class Storage(uri: Optional[str] = None, **options: Union[float, str, bool])[source]#
Base class to extend when implementing a storage backend.
- class MovingWindowSupport[source]#
Abstract base for storages that intend to support the moving window strategy
Async variants#
- class Storage(uri: Optional[str] = None, **options: Union[float, str, bool])[source]#
Base class to extend when implementing an async storage backend.
New in version 2.1.
Rate Limits#
Provided by limits
Parsing functions#
- parse(limit_string: str) RateLimitItem [source]#
parses a single rate limit in string notation (e.g.
1/second
or1 per second
)- Parameters
limit_string¶ – rate limit string using Rate limit string notation
- Raises
ValueError – if the string notation is invalid.
- parse_many(limit_string: str) List[RateLimitItem] [source]#
parses rate limits in string notation containing multiple rate limits (e.g.
1/second; 5/minute
)- Parameters
limit_string¶ – rate limit string using Rate limit string notation
- Raises
ValueError – if the string notation is invalid.
Rate limit granularities#
All rate limit items implement RateLimitItem
by
declaring a GRANULARITY
- class RateLimitItem(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
defines a Rate limited resource which contains the characteristic namespace, amount and granularity multiples of the rate limiting window.
- Parameters
amount¶ – the rate limit amount
multiples¶ – multiple of the ‘per’
GRANULARITY
(e.g. ‘n’ per ‘m’ seconds)namespace¶ – category for the specific rate limit
- GRANULARITY: ClassVar[limits.limits.Granularity]#
A tuple describing the granularity of this limit as (number of seconds, name)
- classmethod check_granularity_string(granularity_string: str) bool [source]#
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY
- class RateLimitItemPerSecond(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
per second rate limited resource.
- classmethod check_granularity_string(granularity_string: str) bool #
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY
- key_for(*identifiers: str) str #
Constructs a key for the current limit and any additional identifiers provided.
- Parameters
identifiers¶ – a list of strings to append to the key
- Returns
a string key identifying this resource with each identifier appended with a ‘/’ delimiter.
- GRANULARITY: ClassVar[limits.limits.Granularity] = Granularity(seconds=1, name='second')#
A second
- class RateLimitItemPerMinute(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
per minute rate limited resource.
- classmethod check_granularity_string(granularity_string: str) bool #
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY
- key_for(*identifiers: str) str #
Constructs a key for the current limit and any additional identifiers provided.
- Parameters
identifiers¶ – a list of strings to append to the key
- Returns
a string key identifying this resource with each identifier appended with a ‘/’ delimiter.
- GRANULARITY: ClassVar[limits.limits.Granularity] = Granularity(seconds=60, name='minute')#
A minute
- class RateLimitItemPerHour(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
per hour rate limited resource.
- GRANULARITY: ClassVar[limits.limits.Granularity] = Granularity(seconds=3600, name='hour')#
An hour
- classmethod check_granularity_string(granularity_string: str) bool #
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY
- class RateLimitItemPerDay(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
per day rate limited resource.
- GRANULARITY: ClassVar[limits.limits.Granularity] = Granularity(seconds=86400, name='day')#
A day
- classmethod check_granularity_string(granularity_string: str) bool #
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY
- class RateLimitItemPerMonth(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
per month rate limited resource.
- GRANULARITY: ClassVar[limits.limits.Granularity] = Granularity(seconds=2592000, name='month')#
A month
- classmethod check_granularity_string(granularity_string: str) bool #
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY
- class RateLimitItemPerYear(amount: int, multiples: Optional[int] = 1, namespace: str = 'LIMITER')[source]#
per year rate limited resource.
- GRANULARITY: ClassVar[limits.limits.Granularity] = Granularity(seconds=31104000, name='year')#
A year
- classmethod check_granularity_string(granularity_string: str) bool #
Checks if this instance matches a granularity_string of type
n per hour
,n per minute
etc, by comparing withGRANULARITY