fast-cache-middleware 0.0.3__py3-none-any.whl → 0.0.5__py3-none-any.whl

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.
@@ -1,371 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: fast-cache-middleware
3
- Version: 0.0.3
4
- Summary: Интеллектуальное middleware для кеширования ответов FastAPI
5
- License: MIT
6
- Author: Your Name
7
- Author-email: your.email@example.com
8
- Requires-Python: >=3.11,<4.0
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: Programming Language :: Python :: 3.11
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Programming Language :: Python :: 3.13
14
- Requires-Dist: cachetools (>=5.0.0,<7.0.0)
15
- Requires-Dist: fastapi (>=0.111.1,<1.0.0)
16
- Description-Content-Type: text/markdown
17
-
18
- # FastCacheMiddleware
19
-
20
- 🚀 **Высокопроизводительный ASGI middleware для кеширования с резолюцией роутов**
21
-
22
- ## ✨ Основные особенности
23
-
24
- FastCacheMiddleware использует **подход с резолюцией роутов** - анализирует роуты приложения на старте и извлекает кеш конфигурации из FastAPI dependencies.
25
-
26
- ### 🔧 Как это работает
27
-
28
- 1. **При старте приложения:**
29
- - Middleware анализирует все роуты и их dependencies
30
- - Извлекает `CacheConfig` и `CacheDropConfig` из dependencies
31
- - Создает внутренний индекс роутов с конфигурациями кеширования
32
-
33
- 2. **При обработке запроса:**
34
- - Проверяет HTTP метод (кешируем только GET, инвалидируем для POST/PUT/DELETE)
35
- - Находит соответствующий роут по пути и методу
36
- - Извлекает кеш конфигурацию из предварительно проанализированных dependencies
37
- - Выполняет кеширование или инвалидацию согласно конфигурации
38
-
39
- ### 💡 Преимущества
40
-
41
- - **⚡ Высокая производительность** - предварительный анализ роутов
42
- - **🎯 Простая интеграция** - стандартные FastAPI dependencies
43
- - **🔧 Гибкая настройка** - кастомные функции ключей, TTL на уровне роутов
44
- - **🛡️ Автоматическая инвалидация** - инвалидация кеша при модифицирующих запросах
45
- - **📊 Минимальные накладные расходы** - эффективная работа с большим количеством роутов
46
-
47
- ## 📦 Установка
48
-
49
- ```bash
50
- pip install fast-cache-middleware
51
- ```
52
-
53
- ## 🎯 Быстрый старт
54
-
55
- ```python
56
- from fastapi import FastAPI, Depends
57
- from fast_cache_middleware import FastCacheMiddleware, CacheConfig, CacheDropConfig
58
-
59
- app = FastAPI()
60
-
61
- # Добавляем middleware - он автоматически анализирует роуты
62
- app.add_middleware(FastCacheMiddleware)
63
-
64
- # Функции для создания кеш конфигураций
65
- def cache_5min() -> CacheConfig:
66
- return CacheConfig(max_age=300) # 5 минут
67
-
68
- def cache_with_custom_key() -> CacheConfig:
69
- def custom_key_func(request):
70
- user_id = request.headers.get("user-id", "anonymous")
71
- return f"{request.url.path}:user:{user_id}"
72
-
73
- return CacheConfig(max_age=60, key_func=custom_key_func)
74
-
75
- def invalidate_users() -> CacheDropConfig:
76
- return CacheDropConfig(paths=["/users/*", "/api/users/*"])
77
-
78
- # Роуты с кешированием
79
- @app.get("/users/{user_id}", dependencies=[Depends(cache_5min)])
80
- async def get_user(user_id: int):
81
- """Этот endpoint кешируется на 5 минут."""
82
- # Имитируем загрузку из БД
83
- return {"user_id": user_id, "name": f"User {user_id}"}
84
-
85
- @app.get("/profile", dependencies=[Depends(cache_with_custom_key)])
86
- async def get_profile():
87
- """Кеширование с персонализированным ключом."""
88
- return {"profile": "user profile data"}
89
-
90
- # Роуты с инвалидацией кеша
91
- @app.post("/users/{user_id}", dependencies=[Depends(invalidate_users)])
92
- async def update_user(user_id: int, data: dict):
93
- """POST запрос инвалидирует кеш для всех /users/* путей."""
94
- return {"user_id": user_id, "status": "updated"}
95
- ```
96
-
97
- ## 🔧 Конфигурация
98
-
99
- ### CacheConfig
100
-
101
- Настройка кеширования для GET запросов:
102
-
103
- ```python
104
- from fast_cache_middleware import CacheConfig
105
-
106
- # Простое кеширование
107
- def simple_cache() -> CacheConfig:
108
- return CacheConfig(max_age=300) # 5 минут
109
-
110
- # С кастомной функцией ключа
111
- def personalized_cache() -> CacheConfig:
112
- def key_func(request):
113
- user_id = request.headers.get("user-id", "anonymous")
114
- path = request.url.path
115
- query = str(request.query_params)
116
- return f"{path}:{user_id}:{query}"
117
-
118
- return CacheConfig(
119
- max_age=600, # 10 минут
120
- key_func=key_func
121
- )
122
-
123
- @app.get("/api/data", dependencies=[Depends(personalized_cache)])
124
- async def get_data():
125
- return {"data": "personalized response"}
126
- ```
127
-
128
- ### CacheDropConfig
129
-
130
- Настройка инвалидации кеша для модифицирующих запросов:
131
-
132
- ```python
133
- from fast_cache_middleware import CacheDropConfig
134
-
135
- def invalidate_multiple_paths() -> CacheDropConfig:
136
- return CacheDropConfig(paths=[
137
- "/users/*", # Все пути пользователей
138
- "/api/users/*", # API пользователей
139
- "/cache/users/*" # Кеш пользователей
140
- ])
141
-
142
- @app.post("/users/{user_id}")
143
- @app.put("/users/{user_id}")
144
- @app.delete("/users/{user_id}")
145
- async def modify_user(user_id: int):
146
- """Любой из этих запросов инвалидирует кеш."""
147
- return {"message": "User modified"}
148
- ```
149
-
150
- ## 🏗️ Архитектура
151
-
152
- ### Компоненты системы
153
-
154
- ```
155
- FastCacheMiddleware
156
- ├── RouteInfo # Информация о роуте с кеш конфигурацией
157
- ├── Controller # Логика кеширования и валидации
158
- ├── Storage # Хранилища (InMemory, Redis, и др.)
159
- ├── Serializers # Сериализация кешированных данных
160
- └── Dependencies # FastAPI dependencies для конфигурации
161
- ```
162
-
163
- ### Поток обработки запроса
164
-
165
- ```mermaid
166
- graph TD
167
- A[HTTP Request] --> B{Анализ роутов выполнен?}
168
- B -->|Нет| C[Анализировать роуты приложения]
169
- C --> D[Сохранить конфигурации роутов]
170
- B -->|Да| E{Метод поддерживает кеширование?}
171
- D --> E
172
- E -->|Нет| F[Передать в приложение]
173
- E -->|Да| G[Найти соответствующий роут]
174
- G --> H{Роут найден?}
175
- H -->|Нет| F
176
- H -->|Да| I{GET запрос + CacheConfig?}
177
- I -->|Да| J[Проверить кеш]
178
- J --> K{Кеш найден?}
179
- K -->|Да| L[Вернуть из кеша]
180
- K -->|Нет| M[Выполнить запрос + сохранить в кеш]
181
- I -->|Нет| N{POST/PUT/DELETE + CacheDropConfig?}
182
- N -->|Да| O[Инвалидировать кеш]
183
- N -->|Нет| F
184
- O --> F
185
- M --> P[Вернуть ответ]
186
- ```
187
-
188
- ## 🎛️ Хранилища
189
-
190
- ### InMemoryStorage (по умолчанию)
191
-
192
- ```python
193
- from fast_cache_middleware import FastCacheMiddleware, InMemoryStorage
194
-
195
- storage = InMemoryStorage(
196
- max_size=1000, # Максимум записей
197
- cleanup_interval=3600 # Очистка каждый час
198
- )
199
- app.add_middleware(FastCacheMiddleware, storage=storage)
200
- ```
201
-
202
- ### Кастомное хранилище
203
-
204
- ```python
205
- from fast_cache_middleware import BaseStorage
206
-
207
- class RedisStorage(BaseStorage):
208
- def __init__(self, redis_url: str):
209
- import redis
210
- self.redis = redis.from_url(redis_url)
211
-
212
- async def store(self, key: str, response, request, metadata):
213
- # Реализация сохранения в Redis
214
- pass
215
-
216
- async def retrieve(self, key: str):
217
- # Реализация извлечения из Redis
218
- pass
219
-
220
- app.add_middleware(FastCacheMiddleware, storage=RedisStorage("redis://localhost"))
221
- ```
222
-
223
- ## 🧪 Тестирование
224
-
225
- ```python
226
- import pytest
227
- from httpx import AsyncClient
228
- from examples.basic import app
229
-
230
- @pytest.mark.asyncio
231
- async def test_caching():
232
- async with AsyncClient(app=app, base_url="http://test") as client:
233
- # Первый запрос - cache miss
234
- response1 = await client.get("/users/1")
235
- assert response1.status_code == 200
236
-
237
- # Второй запрос - cache hit (должен быть быстрее)
238
- response2 = await client.get("/users/1")
239
- assert response2.status_code == 200
240
- assert response1.json() == response2.json()
241
-
242
- @pytest.mark.asyncio
243
- async def test_cache_invalidation():
244
- async with AsyncClient(app=app, base_url="http://test") as client:
245
- # Кешируем данные
246
- await client.get("/users/1")
247
-
248
- # Инвалидируем кеш
249
- await client.post("/users/1", json={})
250
-
251
- # Следующий GET должен выполнить новый запрос
252
- response = await client.get("/users/1")
253
- assert response.status_code == 200
254
- ```
255
-
256
- ## 📊 Производительность
257
-
258
- ### Бенчмарки
259
-
260
- - **Анализ роутов**: ~5ms для 100 роутов при старте
261
- - **Поиск роута**: ~0.1ms на запрос (O(n) по количеству кешируемых роутов)
262
- - **Cache hit**: ~1ms на запрос
263
- - **Cache miss**: время оригинального запроса + ~2ms на сохранение
264
-
265
- ### Оптимизация
266
-
267
- ```python
268
- # Для приложений с большим количеством роутов
269
- app.add_middleware(
270
- FastCacheMiddleware,
271
- storage=InMemoryStorage(max_size=10000), # Увеличить размер кеша
272
- controller=Controller(default_ttl=3600) # Увеличить TTL по умолчанию
273
- )
274
- ```
275
-
276
- ## 🔒 Безопасность
277
-
278
- ### Изоляция кеша
279
-
280
- ```python
281
- def user_specific_cache() -> CacheConfig:
282
- def secure_key_func(request):
283
- # Включаем токен пользователя в ключ
284
- token = request.headers.get("authorization", "").split(" ")[-1]
285
- return f"{request.url.path}:token:{token}"
286
-
287
- return CacheConfig(max_age=300, key_func=secure_key_func)
288
-
289
- @app.get("/private/data", dependencies=[Depends(user_specific_cache)])
290
- async def get_private_data():
291
- return {"sensitive": "data"}
292
- ```
293
-
294
- ### Валидация заголовков
295
-
296
- Middleware автоматически учитывает стандартные HTTP заголовки кеширования:
297
-
298
- - `Cache-Control: no-cache` - пропуск кеша
299
- - `Cache-Control: no-store` - запрет кеширования
300
- - `If-None-Match` - проверка ETag
301
- - `If-Modified-Since` - проверка времени модификации
302
-
303
- ## 🛠️ Продвинутое использование
304
-
305
- ### Кастомный Controller
306
-
307
- ```python
308
- from fast_cache_middleware import Controller
309
-
310
- class CustomController(Controller):
311
- async def should_cache_request(self, request):
312
- # Кастомная логика - не кешируем админские запросы
313
- if request.headers.get("x-admin-request"):
314
- return False
315
- return await super().should_cache_request(request)
316
-
317
- async def generate_cache_key(self, request):
318
- # Добавляем версию API в ключ
319
- version = request.headers.get("api-version", "v1")
320
- base_key = await super().generate_cache_key(request)
321
- return f"{version}:{base_key}"
322
-
323
- app.add_middleware(
324
- FastCacheMiddleware,
325
- controller=CustomController()
326
- )
327
- ```
328
-
329
- ### Мониторинг
330
-
331
- ```python
332
- @app.get("/admin/cache/stats")
333
- async def cache_stats():
334
- # В production здесь будет реальная статистика из storage
335
- return {
336
- "total_routes": len(app.routes),
337
- "cached_routes": "статистика по кешируемым роутам",
338
- "cache_hit_rate": "процент попаданий в кеш",
339
- "storage_size": "размер хранилища"
340
- }
341
- ```
342
-
343
- ## 📝 Примеры
344
-
345
- Больше примеров в папке `examples/`:
346
-
347
- - **basic.py** - базовое использование с FastAPI
348
- - **advanced.py** - продвинутые сценарии
349
- - **custom_storage.py** - интеграция с Redis/Memcached
350
- - **monitoring.py** - мониторинг и метрики
351
-
352
- ## 🤝 Участие в разработке
353
-
354
- ```bash
355
- git clone https://github.com/your-username/fast-cache-middleware
356
- cd fast-cache-middleware
357
- pip install -e ".[dev]"
358
- pytest
359
- ```
360
-
361
- ## 📄 Лицензия
362
-
363
- MIT License - см. [LICENSE](LICENSE)
364
-
365
- ---
366
-
367
- ⭐ **Нравится проект? Поставьте звездочку!**
368
-
369
- 🐛 **Нашли баг?** [Создайте issue](https://github.com/your-username/fast-cache-middleware/issues)
370
-
371
- 💡 **Есть идея?** [Предложите feature](https://github.com/your-username/fast-cache-middleware/discussions)
@@ -1,11 +0,0 @@
1
- fast_cache_middleware/__init__.py,sha256=0wuBPKrzjyBA2K9Fnm-xzC1mYSXCMuYr1uPutNXCI5Y,983
2
- fast_cache_middleware/controller.py,sha256=Y0StElopHiBHa-TjLqi1yoldWkcGZubcCgT2xj2zpEI,7181
3
- fast_cache_middleware/depends.py,sha256=00ShPXlG0A_Ylj0ypLGU0hgSNeLxHeI3PGi8Fo35wko,1867
4
- fast_cache_middleware/exceptions.py,sha256=lv3p2-wAj6UZI7czVSy91eZtuXItr1hZHW2LDz8fI9s,109
5
- fast_cache_middleware/middleware.py,sha256=a80t7jL0CgSmtXaEgrZW-7i6IrggNlTsHGyL1Ri8Oxw,9761
6
- fast_cache_middleware/schemas.py,sha256=uOceBR4_itlj1NG3xszyLbE96bS_W6t6BGmPPkNkoqA,610
7
- fast_cache_middleware/serializers.py,sha256=jf308cez8jVzTikK6BhzHhvuIrGkA8Vdn_Gopd6dfyM,2907
8
- fast_cache_middleware/storages.py,sha256=GEeA-I0QvK6M_mAub08npxylLQ_WEBGyrjt9Zhe_r6A,7611
9
- fast_cache_middleware-0.0.3.dist-info/METADATA,sha256=GPYuWY3YHPjjqhp2xSp7xgUQgoEmZ33EOjntmSvQkOE,13704
10
- fast_cache_middleware-0.0.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
- fast_cache_middleware-0.0.3.dist-info/RECORD,,