0
# Core Rate Limiting
1
2
The main Limiter class provides the primary rate limiting functionality with support for both synchronous and asynchronous operations, configurable delays, and exception handling.
3
4
## Capabilities
5
6
### Limiter Class
7
8
The central class for rate limiting operations, orchestrating rate limit checking, delay handling, and exception management.
9
10
```python { .api }
11
class Limiter:
12
def __init__(
13
self,
14
argument: Union[BucketFactory, AbstractBucket, Rate, List[Rate]],
15
clock: Optional[AbstractClock] = None,
16
raise_when_fail: bool = True,
17
max_delay: Optional[Union[int, Duration]] = None,
18
retry_until_max_delay: bool = False,
19
buffer_ms: int = 50
20
):
21
"""
22
Initialize Limiter with rate limiting configuration.
23
24
Parameters:
25
- argument: Rate configuration, bucket, or bucket factory
26
- clock: Time source for rate calculations (default: TimeClock)
27
- raise_when_fail: Raise exception when rate limit exceeded (default: True)
28
- max_delay: Maximum delay allowed for rate limiting operations
29
- retry_until_max_delay: Retry operations until max delay reached
30
- buffer_ms: Buffer time in milliseconds for delay calculations
31
"""
32
```
33
34
### Synchronous Rate Limiting
35
36
Basic rate limiting operations for synchronous code.
37
38
```python { .api }
39
def try_acquire(self, name: str, weight: int = 1) -> Union[bool, Awaitable[bool]]:
40
"""
41
Try to acquire permission for a rate-limited operation.
42
43
Parameters:
44
- name: Identifier for the rate-limited resource
45
- weight: Weight/cost of the operation (default: 1)
46
47
Returns:
48
- bool: True if operation is allowed, False if rate limited
49
- Awaitable[bool]: For async buckets, returns awaitable boolean
50
"""
51
```
52
53
Usage example:
54
55
```python
56
from pyrate_limiter import Limiter, Rate, Duration
57
58
# Create limiter with 10 requests per minute
59
limiter = Limiter(Rate(10, Duration.MINUTE))
60
61
# Check if request is allowed
62
if limiter.try_acquire("user123"):
63
print("Request allowed")
64
# Proceed with operation
65
else:
66
print("Rate limit exceeded")
67
# Handle rate limiting
68
69
# Weighted requests (e.g., expensive operations)
70
if limiter.try_acquire("bulk_operation", weight=5):
71
print("Bulk operation allowed")
72
```
73
74
### Asynchronous Rate Limiting
75
76
Rate limiting for asynchronous code with proper async/await handling.
77
78
```python { .api }
79
async def try_acquire_async(self, name: str, weight: int = 1) -> bool:
80
"""
81
Async version of try_acquire with thread-local async locking.
82
83
Parameters:
84
- name: Identifier for the rate-limited resource
85
- weight: Weight/cost of the operation (default: 1)
86
87
Returns:
88
- bool: True if operation is allowed, False if rate limited
89
"""
90
```
91
92
Usage example:
93
94
```python
95
import asyncio
96
from pyrate_limiter import Limiter, Rate, Duration
97
98
async def async_example():
99
limiter = Limiter(Rate(5, Duration.SECOND))
100
101
# Async rate limiting
102
if await limiter.try_acquire_async("async_user"):
103
print("Async request allowed")
104
# Proceed with async operation
105
await some_async_operation()
106
else:
107
print("Async rate limit exceeded")
108
```
109
110
### Decorator Pattern
111
112
Function decoration for automatic rate limiting.
113
114
```python { .api }
115
def as_decorator(self) -> Callable[[ItemMapping], DecoratorWrapper]:
116
"""
117
Create decorator for automatic rate limiting of functions.
118
119
Returns:
120
- Callable: Decorator factory function
121
"""
122
```
123
124
Usage example:
125
126
```python
127
from pyrate_limiter import Limiter, Rate, Duration
128
129
limiter = Limiter(Rate(10, Duration.MINUTE))
130
131
# Decorator with mapping function
132
@limiter.as_decorator()
133
def extract_user_info(*args, **kwargs):
134
# Extract name and weight from function arguments
135
user_id = args[0] if args else kwargs.get('user_id', 'default')
136
weight = kwargs.get('weight', 1)
137
return (user_id, weight)
138
139
@extract_user_info
140
def api_call(user_id, data=None, weight=1):
141
return f"Processing API call for {user_id}"
142
143
# Async decorator support
144
@limiter.as_decorator()
145
def async_extract_info(*args, **kwargs):
146
return (args[0], 1)
147
148
@async_extract_info
149
async def async_api_call(user_id):
150
await asyncio.sleep(0.1)
151
return f"Async processing for {user_id}"
152
```
153
154
### Bucket Management
155
156
Managing and inspecting rate limiter state.
157
158
```python { .api }
159
def buckets(self) -> List[AbstractBucket]:
160
"""Get list of active buckets."""
161
162
def dispose(self, bucket: Union[int, AbstractBucket]) -> bool:
163
"""
164
Dispose/remove a specific bucket.
165
166
Parameters:
167
- bucket: Bucket object or bucket ID to remove
168
169
Returns:
170
- bool: True if bucket was removed successfully
171
"""
172
173
def close(self) -> None:
174
"""Release resources held by the limiter."""
175
```
176
177
### Context Manager Support
178
179
Using Limiter as a context manager for automatic resource cleanup.
180
181
```python { .api }
182
def __enter__(self):
183
"""Enter context manager."""
184
185
def __exit__(self, exc_type, exc, tb) -> None:
186
"""Exit context manager and cleanup resources."""
187
```
188
189
Usage example:
190
191
```python
192
from pyrate_limiter import Limiter, Rate, Duration
193
194
# Automatic cleanup with context manager
195
with Limiter(Rate(5, Duration.SECOND)) as limiter:
196
success = limiter.try_acquire("user123")
197
if success:
198
print("Request processed")
199
# Resources automatically cleaned up here
200
```
201
202
### Multiple Rate Limits
203
204
Configuring multiple rate limits for the same resource.
205
206
```python
207
from pyrate_limiter import Limiter, Rate, Duration
208
209
# Multiple rate limits: 10/second AND 100/minute
210
rates = [
211
Rate(10, Duration.SECOND),
212
Rate(100, Duration.MINUTE),
213
Rate(1000, Duration.HOUR)
214
]
215
216
limiter = Limiter(rates)
217
218
# All rate limits must be satisfied
219
if limiter.try_acquire("user123"):
220
print("All rate limits satisfied")
221
```
222
223
## Delay Handling
224
225
When `max_delay` is configured, the limiter can wait for rate limits to reset instead of immediately failing.
226
227
```python
228
from pyrate_limiter import Limiter, Rate, Duration
229
230
# Configure with delay handling
231
limiter = Limiter(
232
Rate(5, Duration.SECOND),
233
max_delay=Duration.SECOND * 2, # Wait up to 2 seconds
234
retry_until_max_delay=True # Keep retrying within delay window
235
)
236
237
# This may block/delay if rate limited
238
success = limiter.try_acquire("user123")
239
```