throttled-py 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. throttled_py-1.0.0/LICENSE +21 -0
  2. throttled_py-1.0.0/PKG-INFO +297 -0
  3. throttled_py-1.0.0/README.md +279 -0
  4. throttled_py-1.0.0/pyproject.toml +90 -0
  5. throttled_py-1.0.0/throttled/__init__.py +56 -0
  6. throttled_py-1.0.0/throttled/constants.py +21 -0
  7. throttled_py-1.0.0/throttled/exceptions.py +36 -0
  8. throttled_py-1.0.0/throttled/rate_limter/__init__.py +39 -0
  9. throttled_py-1.0.0/throttled/rate_limter/base.py +221 -0
  10. throttled_py-1.0.0/throttled/rate_limter/fixed_window.py +112 -0
  11. throttled_py-1.0.0/throttled/rate_limter/gcra.py +248 -0
  12. throttled_py-1.0.0/throttled/rate_limter/leaking_bucket.py +158 -0
  13. throttled_py-1.0.0/throttled/rate_limter/lua/fixed_window.lua +10 -0
  14. throttled_py-1.0.0/throttled/rate_limter/lua/gcra.lua +49 -0
  15. throttled_py-1.0.0/throttled/rate_limter/lua/gcra_peek.lua +39 -0
  16. throttled_py-1.0.0/throttled/rate_limter/lua/leaking_bucket.lua +27 -0
  17. throttled_py-1.0.0/throttled/rate_limter/lua/sliding_window.lua +21 -0
  18. throttled_py-1.0.0/throttled/rate_limter/lua/token_bucket.lua +27 -0
  19. throttled_py-1.0.0/throttled/rate_limter/sliding_window.py +140 -0
  20. throttled_py-1.0.0/throttled/rate_limter/token_bucket.py +157 -0
  21. throttled_py-1.0.0/throttled/store/__init__.py +23 -0
  22. throttled_py-1.0.0/throttled/store/base.py +140 -0
  23. throttled_py-1.0.0/throttled/store/memory.py +179 -0
  24. throttled_py-1.0.0/throttled/store/redis.py +95 -0
  25. throttled_py-1.0.0/throttled/store/redis_pool.py +215 -0
  26. throttled_py-1.0.0/throttled/throttled.py +109 -0
  27. throttled_py-1.0.0/throttled/types.py +13 -0
  28. throttled_py-1.0.0/throttled/utils.py +59 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 crayon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,297 @@
1
+ Metadata-Version: 2.1
2
+ Name: throttled-py
3
+ Version: 1.0.0
4
+ Summary: 🔧 High-performance Python rate limiting library with multiple algorithms (Fixed Window, Sliding Window, Token Bucket, Leaky Bucket & GCRA) and storage backends (Redis, In-Memory).
5
+ Author: ZhuoZhuoCrayon
6
+ Author-email: crayon.ccxx@gmail.com
7
+ Requires-Python: >=3.8,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: redis (>=5.2.1,<6.0.0)
16
+ Description-Content-Type: text/markdown
17
+
18
+ <h1 align="center">throttled-py</h1>
19
+ <p align="center">
20
+ <em>🔧 支持多种算法(固定窗口,滑动窗口,令牌桶,漏桶 & GCRA)及存储(Redis、内存)的高性能 Python 限流库。</em>
21
+ </p>
22
+
23
+ <p align="center">
24
+ <a href="https://github.com/ZhuoZhuoCrayon/throttled-py">
25
+ <img src="https://badgen.net/badge/python/%3E=3.8/green?icon=github" alt="Python">
26
+ </a>
27
+ <a href="https://github.com/ZhuoZhuoCrayon/throttled-py">
28
+ <img src="https://codecov.io/gh/ZhuoZhuoCrayon/throttled-py/graph/badge.svg" alt="Coverage Status">
29
+ </a>
30
+ </p>
31
+
32
+ [English Documents Available](./README_EN.md) | 简体中文
33
+
34
+
35
+ ## :rocket: 功能
36
+
37
+ ### 1)存储
38
+
39
+ | Redis | 内存(线程安全) |
40
+ |--------------------|--------------------|
41
+ | :white_check_mark: | :white_check_mark: |
42
+
43
+ ### 2)限流算法
44
+
45
+ | [固定窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/tree/main/docs/basic#21-%E5%9B%BA%E5%AE%9A%E7%AA%97%E5%8F%A3%E8%AE%A1%E6%95%B0%E5%99%A8) | [滑动窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#22-%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3) | [令牌桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#23-%E4%BB%A4%E7%89%8C%E6%A1%B6) | [漏桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#24-%E6%BC%8F%E6%A1%B6) | [通用信元速率算法(Generic Cell Rate Algorithm, GCRA)](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#25-gcra) |
46
+ |------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
47
+ | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
48
+
49
+ 我们提供以上限流算法的原理分析,你可以点击具体的限流算法跳转到相应的介绍。
50
+
51
+
52
+ ## :beginner: 安装
53
+
54
+ ```shell
55
+ $ pip install throttled-py
56
+ ```
57
+
58
+
59
+ ## :memo: 使用
60
+
61
+ ### 1)基础
62
+
63
+ #### 通用 API
64
+
65
+ * `limit`:消耗请求,返回 [**RateLimitResult**](https://github.com/ZhuoZhuoCrayon/throttled-py?tab=readme-ov-file#1ratelimitresult)。
66
+ * `peek`:获取指定 Key 的限流器状态,返回 [**RateLimitState**](https://github.com/ZhuoZhuoCrayon/throttled-py?tab=readme-ov-file#2ratelimitstate)。
67
+
68
+ ```python
69
+ from throttled import Throttled
70
+
71
+ # 参数全部缺省时,默认初始化一个基于「内存」、每秒允许通过 60 个请求、使用「令牌桶算法」的限流器。
72
+ throttle = Throttled()
73
+
74
+ # 消耗 1 次请求,输出:RateLimitResult(limited=False,
75
+ # state=RateLimitState(limit=60, remaining=59, reset_after=1))
76
+ print(throttle.limit("key", 1))
77
+ # 获取限流器状态,输出:RateLimitState(limit=60, remaining=59, reset_after=1)
78
+ print(throttle.peek("key"))
79
+
80
+ # 消耗 60 次请求,触发限流,输出:RateLimitResult(limited=True,
81
+ # # state=RateLimitState(limit=60, remaining=59, reset_after=1))
82
+ print(throttle.limit("key", 60))
83
+ ```
84
+
85
+ #### 作为装饰器
86
+
87
+ ```python
88
+ from throttled import Throttled, rate_limter, exceptions
89
+
90
+ # 创建一个每秒允许通过 1 次的限流器。
91
+ @Throttled(key="/ping", quota=rate_limter.per_min(1))
92
+ def ping() -> str:
93
+ return "ping"
94
+
95
+ ping()
96
+
97
+ try:
98
+ ping() # 当触发限流时,抛出 LimitedError。
99
+ except exceptions.LimitedError as exc:
100
+ print(exc) # Rate limit exceeded: remaining=0, reset_after=60
101
+ # 在异常中获取限流结果:RateLimitResult(limited=True,
102
+ # state=RateLimitState(limit=1, remaining=0, reset_after=60))
103
+ print(exc.rate_limit_result)
104
+ ```
105
+
106
+ ### 2)指定存储后端
107
+
108
+ #### Redis
109
+
110
+ ```python
111
+ from throttled import RateLimiterType, Throttled, rate_limter, store
112
+
113
+ @Throttled(
114
+ key="/api/products",
115
+ using=RateLimiterType.TOKEN_BUCKET.value,
116
+ quota=rate_limter.per_min(1),
117
+ # 🌟 使用 Redis 作为存储后端
118
+ store=store.RedisStore(server="redis://127.0.0.1:6379/0", options={"PASSWORD": ""}),
119
+ )
120
+ def products() -> list:
121
+ return [{"name": "iPhone"}, {"name": "MacBook"}]
122
+
123
+ products()
124
+ # raise LimitedError: Rate limit exceeded: remaining=0, reset_after=60
125
+ products()
126
+ ```
127
+
128
+ #### Memory
129
+
130
+ 如果你希望在程序的不同位置,对同一个 Key 进行限流,请确保 `Throttled` 接收到的是同一个 `MemoryStore`,并使用一致的 [`Quota`](https://github.com/ZhuoZhuoCrayon/throttled-py?tab=readme-ov-file#3quota)。
131
+
132
+ 下方样例使用内存作为存储后端,并在 `ping`、`pong` 上对同一个 Key 进行限流:
133
+
134
+ ```python
135
+ from throttled import Throttled, rate_limter, store
136
+
137
+ # 🌟 使用 Memory 作为存储后端
138
+ mem_store = store.MemoryStore()
139
+
140
+ @Throttled(key="ping-pong", quota=rate_limter.per_min(1), store=mem_store)
141
+ def ping() -> str:
142
+ return "ping"
143
+
144
+ @Throttled(key="ping-pong", quota=rate_limter.per_min(1), store=mem_store)
145
+ def pong() -> str:
146
+ return "pong"
147
+
148
+ ping()
149
+ # raise LimitedError: Rate limit exceeded: remaining=0, reset_after=60
150
+ pong()
151
+ ```
152
+
153
+ ### 3)指定限流算法
154
+
155
+ 通过 **`using`** 参数指定限流算法,支持算法如下:
156
+
157
+ * [固定窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/tree/main/docs/basic#21-%E5%9B%BA%E5%AE%9A%E7%AA%97%E5%8F%A3%E8%AE%A1%E6%95%B0%E5%99%A8):`RateLimiterType.FIXED_WINDOW.value`
158
+ * [滑动窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#22-%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3):`RateLimiterType.SLIDING_WINDOW.value`
159
+ * [令牌桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#23-%E4%BB%A4%E7%89%8C%E6%A1%B6):`RateLimiterType.TOKEN_BUCKET.value`
160
+ * [漏桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#24-%E6%BC%8F%E6%A1%B6):`RateLimiterType.LEAKING_BUCKET.value`
161
+ * [通用信元速率算法(Generic Cell Rate Algorithm, GCRA)](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#25-gcra):`RateLimiterType.GCRA.value`
162
+
163
+ ```python
164
+ from throttled import RateLimiterType, Throttled, rate_limter, store
165
+
166
+ throttle = Throttled(
167
+ # 🌟指定限流算法
168
+ using=RateLimiterType.FIXED_WINDOW.value,
169
+ quota=rate_limter.per_min(1),
170
+ store=store.MemoryStore()
171
+ )
172
+ assert throttle.limit("key", 2).limited is True
173
+ ```
174
+
175
+ ### 4)指定容量
176
+
177
+ #### 快捷创建方式
178
+
179
+ ```python
180
+ from throttled import rate_limter
181
+
182
+ rate_limter.per_sec(60) # 60 / sec
183
+ rate_limter.per_min(60) # 60 / min
184
+ rate_limter.per_hour(60) # 60 / hour
185
+ rate_limter.per_day(60) # 60 / day
186
+ ```
187
+
188
+ #### 调整突发限制
189
+
190
+ 通过 **`burst`** 参数,可以调节限流对象处理突发流量的能力 ,对以下算法有效:
191
+
192
+ * `TOKEN_BUCKET`
193
+ * `LEAKING_BUCKET`
194
+ * `GCRA`
195
+
196
+ ```python
197
+ from throttled import rate_limter
198
+
199
+ # 允许突发处理 120 个请求
200
+ # 未指定 burst 时,默认设置为 limit 传入值
201
+ rate_limter.per_min(60, burst=120)
202
+ ```
203
+
204
+ #### 自定义配额
205
+
206
+ ```python
207
+ from datetime import timedelta
208
+ from throttled.rate_limter import Quota, Rate
209
+
210
+ # 两分钟一共允许 120 个请求,允许突发处理 150 个请求
211
+ Quota(Rate(period=timedelta(minutes=2), limit=120), burst=150)
212
+ ```
213
+
214
+ ## :gear: 数据模型与配置
215
+
216
+ ### 1)RateLimitResult
217
+
218
+ RateLimitResult 表示对给定 Key 执行 `limit` 操作后返回的结果。
219
+
220
+ | 字段 | 类型 | 描述 |
221
+ |-----------|----------------|--------------------|
222
+ | `limited` | bool | 表示此次请求是否被允许通过。 |
223
+ | `state` | RateLimitState | 表示给定 Key 的限流器当前状态。 |
224
+
225
+ ### 2)RateLimitState
226
+
227
+ RateLimitState 表示给定 Key 的限流器当前状态。
228
+
229
+ | 字段 | 类型 | 描述 |
230
+ |---------------|-------|---------------------------------------------------------|
231
+ | `limit` | int | 表示在初始状态下允许通过的最大请求数量。 |
232
+ | `remaining` | int | 表示在当前状态下,针对给定键允许通过的最大请求数量。 |
233
+ | `reset_after` | float | 表示限流器恢复到初始状态所需的时间(以秒为单位)。在初始状态下,`limit` 等于 `remaining`。 |
234
+
235
+ ### 3)Quota
236
+
237
+ Quota 表示限流配额(基础速率 + 突发容量)。
238
+
239
+ | 字段 | 类型 | 描述 |
240
+ |---------|------|-------------------------------------------------------------------------------------|
241
+ | `burst` | int | 突发容量配置(可临时突破基础速率限制),仅对以下算法生效:<br />`TOEKN_BUCKET`<br />`LEAKING_BUCKET`<br />`GCRA` |
242
+ | `rate` | Rate | 基础速率配置。 |
243
+
244
+ ### 4)Rate
245
+
246
+ Rate 表示限流速率配置((时间窗口内允许的请求量)。
247
+
248
+ | 字段 | 类型 | 描述 |
249
+ |----------|--------------------|----------------|
250
+ | `period` | datetime.timedelta | 限流时间窗口。 |
251
+ | `limit` | Rate | 时间窗口内允许的最大请求数。 |
252
+
253
+ ### 5)Store
254
+
255
+ #### 通用参数
256
+
257
+ | 参数 | 描述 | 默认值 |
258
+ |-----------|-----------------------------------------------------------------------------------------------------|------------------------------|
259
+ | `server` | 标准的 [Redis URL](https://github.com/redis/lettuce/wiki/Redis-URI-and-connection-details#uri-syntax)。 | `"redis://localhost:6379/0"` |
260
+ | `options` | 存储相关配置项,见下文。 | `{}` |
261
+
262
+ #### RedisStore Options
263
+
264
+ RedisStore 基于 [redis-py](https://github.com/redis/redis-py) 提供的 Redis API 进行开发。
265
+
266
+ 在 Redis 连接配置管理上,基本沿用 [django-redis](https://github.com/jazzband/django-redis) 的配置命名,减少学习成本。
267
+
268
+ | 参数 | 描述 | 默认值 |
269
+ |----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
270
+ | `CONNECTION_FACTORY_CLASS` | ConnectionFactory 用于创建并维护 [ConnectionPool](https://redis-py.readthedocs.io/en/stable/connections.html#redis.connection.ConnectionPool)。 | `"throttled.store.ConnectionFactory"` |
271
+ | `CONNECTION_POOL_CLASS` | ConnectionPool 导入路径。 | `"redis.connection.ConnectionPool"` |
272
+ | `CONNECTION_POOL_KWARGS` | [ConnectionPool 构造参数](https://redis-py.readthedocs.io/en/stable/connections.html#connectionpool)。 | `{}` |
273
+ | `REDIS_CLIENT_CLASS` | RedisClient 导入路径,默认使用 [redis.client.Redis](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis)。 | `"redis.client.Redis"` |
274
+ | `REDIS_CLIENT_KWARGS` | [RedisClient 构造参数](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis)。 | `{}` |
275
+ | `PASSWORD` | 密码。 | `null` |
276
+ | `SOCKET_TIMEOUT` | ConnectionPool 参数。 | `null` |
277
+ | `SOCKET_CONNECT_TIMEOUT` | ConnectionPool 参数。 | `null` |
278
+ | `SENTINELS` | `(host, port)` 元组列表,哨兵模式请使用 `SentinelConnectionFactory` 并提供该配置。 | `[]` |
279
+ | `SENTINEL_KWARGS` | [Sentinel 构造参数](https://redis-py.readthedocs.io/en/stable/connections.html#id1)。 | `{}` |
280
+
281
+ #### MemoryStore Options
282
+
283
+ MemoryStore 本质是一个基于内存实现的,带过期时间的 [LRU Cache](https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU) 。
284
+
285
+ | 参数 | 描述 | 默认值 |
286
+ |------------|-------------------------------------------|--------|
287
+ | `MAX_SIZE` | 最大容量,存储的键值对数量超过 `MAX_SIZE` 时,将按 LRU 策略淘汰。 | `1024` |
288
+
289
+
290
+ ## :books: Version History
291
+
292
+ [See CHANGELOG.md](./CHANGELOG.md)
293
+
294
+ ## :page_facing_up: License
295
+
296
+ [The MIT License](./LICENSE)
297
+
@@ -0,0 +1,279 @@
1
+ <h1 align="center">throttled-py</h1>
2
+ <p align="center">
3
+ <em>🔧 支持多种算法(固定窗口,滑动窗口,令牌桶,漏桶 & GCRA)及存储(Redis、内存)的高性能 Python 限流库。</em>
4
+ </p>
5
+
6
+ <p align="center">
7
+ <a href="https://github.com/ZhuoZhuoCrayon/throttled-py">
8
+ <img src="https://badgen.net/badge/python/%3E=3.8/green?icon=github" alt="Python">
9
+ </a>
10
+ <a href="https://github.com/ZhuoZhuoCrayon/throttled-py">
11
+ <img src="https://codecov.io/gh/ZhuoZhuoCrayon/throttled-py/graph/badge.svg" alt="Coverage Status">
12
+ </a>
13
+ </p>
14
+
15
+ [English Documents Available](./README_EN.md) | 简体中文
16
+
17
+
18
+ ## :rocket: 功能
19
+
20
+ ### 1)存储
21
+
22
+ | Redis | 内存(线程安全) |
23
+ |--------------------|--------------------|
24
+ | :white_check_mark: | :white_check_mark: |
25
+
26
+ ### 2)限流算法
27
+
28
+ | [固定窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/tree/main/docs/basic#21-%E5%9B%BA%E5%AE%9A%E7%AA%97%E5%8F%A3%E8%AE%A1%E6%95%B0%E5%99%A8) | [滑动窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#22-%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3) | [令牌桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#23-%E4%BB%A4%E7%89%8C%E6%A1%B6) | [漏桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#24-%E6%BC%8F%E6%A1%B6) | [通用信元速率算法(Generic Cell Rate Algorithm, GCRA)](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#25-gcra) |
29
+ |------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------|
30
+ | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
31
+
32
+ 我们提供以上限流算法的原理分析,你可以点击具体的限流算法跳转到相应的介绍。
33
+
34
+
35
+ ## :beginner: 安装
36
+
37
+ ```shell
38
+ $ pip install throttled-py
39
+ ```
40
+
41
+
42
+ ## :memo: 使用
43
+
44
+ ### 1)基础
45
+
46
+ #### 通用 API
47
+
48
+ * `limit`:消耗请求,返回 [**RateLimitResult**](https://github.com/ZhuoZhuoCrayon/throttled-py?tab=readme-ov-file#1ratelimitresult)。
49
+ * `peek`:获取指定 Key 的限流器状态,返回 [**RateLimitState**](https://github.com/ZhuoZhuoCrayon/throttled-py?tab=readme-ov-file#2ratelimitstate)。
50
+
51
+ ```python
52
+ from throttled import Throttled
53
+
54
+ # 参数全部缺省时,默认初始化一个基于「内存」、每秒允许通过 60 个请求、使用「令牌桶算法」的限流器。
55
+ throttle = Throttled()
56
+
57
+ # 消耗 1 次请求,输出:RateLimitResult(limited=False,
58
+ # state=RateLimitState(limit=60, remaining=59, reset_after=1))
59
+ print(throttle.limit("key", 1))
60
+ # 获取限流器状态,输出:RateLimitState(limit=60, remaining=59, reset_after=1)
61
+ print(throttle.peek("key"))
62
+
63
+ # 消耗 60 次请求,触发限流,输出:RateLimitResult(limited=True,
64
+ # # state=RateLimitState(limit=60, remaining=59, reset_after=1))
65
+ print(throttle.limit("key", 60))
66
+ ```
67
+
68
+ #### 作为装饰器
69
+
70
+ ```python
71
+ from throttled import Throttled, rate_limter, exceptions
72
+
73
+ # 创建一个每秒允许通过 1 次的限流器。
74
+ @Throttled(key="/ping", quota=rate_limter.per_min(1))
75
+ def ping() -> str:
76
+ return "ping"
77
+
78
+ ping()
79
+
80
+ try:
81
+ ping() # 当触发限流时,抛出 LimitedError。
82
+ except exceptions.LimitedError as exc:
83
+ print(exc) # Rate limit exceeded: remaining=0, reset_after=60
84
+ # 在异常中获取限流结果:RateLimitResult(limited=True,
85
+ # state=RateLimitState(limit=1, remaining=0, reset_after=60))
86
+ print(exc.rate_limit_result)
87
+ ```
88
+
89
+ ### 2)指定存储后端
90
+
91
+ #### Redis
92
+
93
+ ```python
94
+ from throttled import RateLimiterType, Throttled, rate_limter, store
95
+
96
+ @Throttled(
97
+ key="/api/products",
98
+ using=RateLimiterType.TOKEN_BUCKET.value,
99
+ quota=rate_limter.per_min(1),
100
+ # 🌟 使用 Redis 作为存储后端
101
+ store=store.RedisStore(server="redis://127.0.0.1:6379/0", options={"PASSWORD": ""}),
102
+ )
103
+ def products() -> list:
104
+ return [{"name": "iPhone"}, {"name": "MacBook"}]
105
+
106
+ products()
107
+ # raise LimitedError: Rate limit exceeded: remaining=0, reset_after=60
108
+ products()
109
+ ```
110
+
111
+ #### Memory
112
+
113
+ 如果你希望在程序的不同位置,对同一个 Key 进行限流,请确保 `Throttled` 接收到的是同一个 `MemoryStore`,并使用一致的 [`Quota`](https://github.com/ZhuoZhuoCrayon/throttled-py?tab=readme-ov-file#3quota)。
114
+
115
+ 下方样例使用内存作为存储后端,并在 `ping`、`pong` 上对同一个 Key 进行限流:
116
+
117
+ ```python
118
+ from throttled import Throttled, rate_limter, store
119
+
120
+ # 🌟 使用 Memory 作为存储后端
121
+ mem_store = store.MemoryStore()
122
+
123
+ @Throttled(key="ping-pong", quota=rate_limter.per_min(1), store=mem_store)
124
+ def ping() -> str:
125
+ return "ping"
126
+
127
+ @Throttled(key="ping-pong", quota=rate_limter.per_min(1), store=mem_store)
128
+ def pong() -> str:
129
+ return "pong"
130
+
131
+ ping()
132
+ # raise LimitedError: Rate limit exceeded: remaining=0, reset_after=60
133
+ pong()
134
+ ```
135
+
136
+ ### 3)指定限流算法
137
+
138
+ 通过 **`using`** 参数指定限流算法,支持算法如下:
139
+
140
+ * [固定窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/tree/main/docs/basic#21-%E5%9B%BA%E5%AE%9A%E7%AA%97%E5%8F%A3%E8%AE%A1%E6%95%B0%E5%99%A8):`RateLimiterType.FIXED_WINDOW.value`
141
+ * [滑动窗口](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#22-%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3):`RateLimiterType.SLIDING_WINDOW.value`
142
+ * [令牌桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#23-%E4%BB%A4%E7%89%8C%E6%A1%B6):`RateLimiterType.TOKEN_BUCKET.value`
143
+ * [漏桶](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#24-%E6%BC%8F%E6%A1%B6):`RateLimiterType.LEAKING_BUCKET.value`
144
+ * [通用信元速率算法(Generic Cell Rate Algorithm, GCRA)](https://github.com/ZhuoZhuoCrayon/throttled-py/blob/main/docs/basic/readme.md#25-gcra):`RateLimiterType.GCRA.value`
145
+
146
+ ```python
147
+ from throttled import RateLimiterType, Throttled, rate_limter, store
148
+
149
+ throttle = Throttled(
150
+ # 🌟指定限流算法
151
+ using=RateLimiterType.FIXED_WINDOW.value,
152
+ quota=rate_limter.per_min(1),
153
+ store=store.MemoryStore()
154
+ )
155
+ assert throttle.limit("key", 2).limited is True
156
+ ```
157
+
158
+ ### 4)指定容量
159
+
160
+ #### 快捷创建方式
161
+
162
+ ```python
163
+ from throttled import rate_limter
164
+
165
+ rate_limter.per_sec(60) # 60 / sec
166
+ rate_limter.per_min(60) # 60 / min
167
+ rate_limter.per_hour(60) # 60 / hour
168
+ rate_limter.per_day(60) # 60 / day
169
+ ```
170
+
171
+ #### 调整突发限制
172
+
173
+ 通过 **`burst`** 参数,可以调节限流对象处理突发流量的能力 ,对以下算法有效:
174
+
175
+ * `TOKEN_BUCKET`
176
+ * `LEAKING_BUCKET`
177
+ * `GCRA`
178
+
179
+ ```python
180
+ from throttled import rate_limter
181
+
182
+ # 允许突发处理 120 个请求
183
+ # 未指定 burst 时,默认设置为 limit 传入值
184
+ rate_limter.per_min(60, burst=120)
185
+ ```
186
+
187
+ #### 自定义配额
188
+
189
+ ```python
190
+ from datetime import timedelta
191
+ from throttled.rate_limter import Quota, Rate
192
+
193
+ # 两分钟一共允许 120 个请求,允许突发处理 150 个请求
194
+ Quota(Rate(period=timedelta(minutes=2), limit=120), burst=150)
195
+ ```
196
+
197
+ ## :gear: 数据模型与配置
198
+
199
+ ### 1)RateLimitResult
200
+
201
+ RateLimitResult 表示对给定 Key 执行 `limit` 操作后返回的结果。
202
+
203
+ | 字段 | 类型 | 描述 |
204
+ |-----------|----------------|--------------------|
205
+ | `limited` | bool | 表示此次请求是否被允许通过。 |
206
+ | `state` | RateLimitState | 表示给定 Key 的限流器当前状态。 |
207
+
208
+ ### 2)RateLimitState
209
+
210
+ RateLimitState 表示给定 Key 的限流器当前状态。
211
+
212
+ | 字段 | 类型 | 描述 |
213
+ |---------------|-------|---------------------------------------------------------|
214
+ | `limit` | int | 表示在初始状态下允许通过的最大请求数量。 |
215
+ | `remaining` | int | 表示在当前状态下,针对给定键允许通过的最大请求数量。 |
216
+ | `reset_after` | float | 表示限流器恢复到初始状态所需的时间(以秒为单位)。在初始状态下,`limit` 等于 `remaining`。 |
217
+
218
+ ### 3)Quota
219
+
220
+ Quota 表示限流配额(基础速率 + 突发容量)。
221
+
222
+ | 字段 | 类型 | 描述 |
223
+ |---------|------|-------------------------------------------------------------------------------------|
224
+ | `burst` | int | 突发容量配置(可临时突破基础速率限制),仅对以下算法生效:<br />`TOEKN_BUCKET`<br />`LEAKING_BUCKET`<br />`GCRA` |
225
+ | `rate` | Rate | 基础速率配置。 |
226
+
227
+ ### 4)Rate
228
+
229
+ Rate 表示限流速率配置((时间窗口内允许的请求量)。
230
+
231
+ | 字段 | 类型 | 描述 |
232
+ |----------|--------------------|----------------|
233
+ | `period` | datetime.timedelta | 限流时间窗口。 |
234
+ | `limit` | Rate | 时间窗口内允许的最大请求数。 |
235
+
236
+ ### 5)Store
237
+
238
+ #### 通用参数
239
+
240
+ | 参数 | 描述 | 默认值 |
241
+ |-----------|-----------------------------------------------------------------------------------------------------|------------------------------|
242
+ | `server` | 标准的 [Redis URL](https://github.com/redis/lettuce/wiki/Redis-URI-and-connection-details#uri-syntax)。 | `"redis://localhost:6379/0"` |
243
+ | `options` | 存储相关配置项,见下文。 | `{}` |
244
+
245
+ #### RedisStore Options
246
+
247
+ RedisStore 基于 [redis-py](https://github.com/redis/redis-py) 提供的 Redis API 进行开发。
248
+
249
+ 在 Redis 连接配置管理上,基本沿用 [django-redis](https://github.com/jazzband/django-redis) 的配置命名,减少学习成本。
250
+
251
+ | 参数 | 描述 | 默认值 |
252
+ |----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|
253
+ | `CONNECTION_FACTORY_CLASS` | ConnectionFactory 用于创建并维护 [ConnectionPool](https://redis-py.readthedocs.io/en/stable/connections.html#redis.connection.ConnectionPool)。 | `"throttled.store.ConnectionFactory"` |
254
+ | `CONNECTION_POOL_CLASS` | ConnectionPool 导入路径。 | `"redis.connection.ConnectionPool"` |
255
+ | `CONNECTION_POOL_KWARGS` | [ConnectionPool 构造参数](https://redis-py.readthedocs.io/en/stable/connections.html#connectionpool)。 | `{}` |
256
+ | `REDIS_CLIENT_CLASS` | RedisClient 导入路径,默认使用 [redis.client.Redis](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis)。 | `"redis.client.Redis"` |
257
+ | `REDIS_CLIENT_KWARGS` | [RedisClient 构造参数](https://redis-py.readthedocs.io/en/stable/connections.html#redis.Redis)。 | `{}` |
258
+ | `PASSWORD` | 密码。 | `null` |
259
+ | `SOCKET_TIMEOUT` | ConnectionPool 参数。 | `null` |
260
+ | `SOCKET_CONNECT_TIMEOUT` | ConnectionPool 参数。 | `null` |
261
+ | `SENTINELS` | `(host, port)` 元组列表,哨兵模式请使用 `SentinelConnectionFactory` 并提供该配置。 | `[]` |
262
+ | `SENTINEL_KWARGS` | [Sentinel 构造参数](https://redis-py.readthedocs.io/en/stable/connections.html#id1)。 | `{}` |
263
+
264
+ #### MemoryStore Options
265
+
266
+ MemoryStore 本质是一个基于内存实现的,带过期时间的 [LRU Cache](https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU) 。
267
+
268
+ | 参数 | 描述 | 默认值 |
269
+ |------------|-------------------------------------------|--------|
270
+ | `MAX_SIZE` | 最大容量,存储的键值对数量超过 `MAX_SIZE` 时,将按 LRU 策略淘汰。 | `1024` |
271
+
272
+
273
+ ## :books: Version History
274
+
275
+ [See CHANGELOG.md](./CHANGELOG.md)
276
+
277
+ ## :page_facing_up: License
278
+
279
+ [The MIT License](./LICENSE)