Metadata-Version: 2.4
Name: async-redis-rate-limiters
Version: 0.0.2
Summary: Rock solid async python generic distributed rate limiters (concurrency and time) backed by Redis.
Project-URL: Homepage, https://github.com/fabien-marty/async-redis-rate-limiters
Project-URL: Repository, https://github.com/fabien-marty/async-redis-rate-limiters.git
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: redis>=6.2.0
Requires-Dist: stlog>=0.5.0
Requires-Dist: tenacity>=9.1.2
Dynamic: license-file

# async-redis-rate-limiters

![Python Badge](https://raw.githubusercontent.com/fabien-marty/common/refs/heads/main/badges/python310plus.svg)
[![UV Badge](https://raw.githubusercontent.com/fabien-marty/common/refs/heads/main/badges/uv.svg)](https://docs.astral.sh/uv/)
[![Mergify Badge](https://raw.githubusercontent.com/fabien-marty/common/refs/heads/main/badges/mergify.svg)](https://mergify.com/)
[![Renovate Badge](https://raw.githubusercontent.com/fabien-marty/common/refs/heads/main/badges/renovate.svg)](https://docs.renovatebot.com/)
[![MIT Licensed](https://raw.githubusercontent.com/fabien-marty/common/refs/heads/main/badges/mit.svg)](https://en.wikipedia.org/wiki/MIT_License)

Rock solid async python generic distributed rate limiters (concurrency and time) backed by Redis.

> [!WARNING]  
> This is a very preliminary version of the library and only concurrency limiters are available for now.

## Features

- ✅ Support very high concurrency (>100K), keep a reasonable number of connections to Redis (default: 300)
- ✅ Rock solid with Redis/Network failures (multiple attempts, exponential backoff, etc.)
- ✅ Very high performances with almost no polling at all

## Non-features

- ❌ No time based rate limiters (yet)
- ❌ No blocking support, only async Python

## Installation

```bash
pip install async-redis-rate-limiters
```

*(or same with your favorite package manager)*

## Usage

```python
import asyncio
from typing import AsyncContextManager
from async_redis_rate_limiters import DistributedSemaphoreManager


async def worker(semaphore: AsyncContextManager):
    async with semaphore:
        # concurrency limit enforced here
        pass


async def main():
    manager = DistributedSemaphoreManager(
        redis_url="redis://localhost:6379",
        redis_max_connections=100,
    )
    # Limit the concurrency to 10 concurrent tasks for the key "test"
    semaphore = manager.get_semaphore("test", 10)
    tasks = [asyncio.create_task(worker(semaphore)) for _ in range(1000)]
    await asyncio.gather(*tasks)


if __name__ == "__main__":
    asyncio.run(main())

```

## Dev

- Lint the code:

`make lint`

- Run the tests:

`make test`
