cachekit 0.14.0__tar.gz → 0.16.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.
- {cachekit-0.14.0 → cachekit-0.16.0}/Cargo.lock +1 -1
- {cachekit-0.14.0 → cachekit-0.16.0}/PKG-INFO +1 -6
- {cachekit-0.14.0 → cachekit-0.16.0}/README.md +0 -4
- {cachekit-0.14.0 → cachekit-0.16.0}/pyproject.toml +1 -3
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/Cargo.toml +1 -1
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/README.md +0 -4
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/__init__.py +1 -2
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/base.py +2 -2
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/cache_handler.py +8 -6
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/config/__init__.py +0 -2
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/config/decorator.py +4 -27
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/config/nested.py +0 -60
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/intent.py +0 -2
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/orchestrator.py +0 -43
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/wrapper.py +1 -36
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/__init__.py +1 -4
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/circuit_breaker.py +37 -83
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/metrics_collection.py +1 -2
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/profiles.py +0 -10
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/encryption_wrapper.py +32 -4
- cachekit-0.14.0/src/cachekit/invalidation/__init__.py +0 -31
- cachekit-0.14.0/src/cachekit/invalidation/channel.py +0 -125
- cachekit-0.14.0/src/cachekit/invalidation/event.py +0 -232
- cachekit-0.14.0/src/cachekit/invalidation/redis_channel.py +0 -403
- cachekit-0.14.0/src/cachekit/reliability/adaptive_timeout.py +0 -424
- {cachekit-0.14.0 → cachekit-0.16.0}/Cargo.toml +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/LICENSE +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/Makefile +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/TEST_EXPANSION_SUMMARY.md +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/src/lib.rs +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/src/python_bindings.rs +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/supply-chain/audits.toml +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/supply-chain/config.toml +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/supply-chain/imports.lock +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/rust/tsan_suppressions.txt +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/base_config.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/cachekitio/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/cachekitio/backend.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/cachekitio/client.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/cachekitio/config.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/cachekitio/error_handler.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/cachekitio/session.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/errors.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/file/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/file/backend.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/file/config.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/memcached/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/memcached/backend.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/memcached/config.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/memcached/error_handler.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/provider.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/redis/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/redis/backend.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/redis/client.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/redis/config.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/redis/error_handler.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/backends/redis/provider.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/config/settings.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/config/singleton.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/config/validation.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/local_wrapper.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/main.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/session.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/stats_context.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/tenant_context.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/decorators/utils/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/di.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/hash_utils.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/health.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/hiredis_compat.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/imports.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/interop.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/key_generator.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/l1_cache.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/logging.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/monitoring/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/monitoring/correlation_tracking.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/monitoring/pool_monitor.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/monitoring/protocols.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/object_cache.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/py.typed +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/async_metrics.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/error_classification.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/reliability/load_control.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/__init__.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/arrow_serializer.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/auto_serializer.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/base.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/interop_serializer.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/orjson_serializer.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/standard_serializer.py +0 -0
- {cachekit-0.14.0 → cachekit-0.16.0}/src/cachekit/serializers/wrapper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cachekit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.0
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -22,7 +22,6 @@ Classifier: Typing :: Typed
|
|
|
22
22
|
Requires-Dist: redis[hiredis]>=4.0.0
|
|
23
23
|
Requires-Dist: pydantic>=2.0.0
|
|
24
24
|
Requires-Dist: pydantic-settings>=2.0.0
|
|
25
|
-
Requires-Dist: tenacity>=8.0.0
|
|
26
25
|
Requires-Dist: prometheus-client>=0.22.1
|
|
27
26
|
Requires-Dist: psutil>=7.0.0
|
|
28
27
|
Requires-Dist: blake3>=1.0.5
|
|
@@ -101,7 +100,6 @@ That's it. You get:
|
|
|
101
100
|
| **Prometheus metrics** | Built-in observability |
|
|
102
101
|
| **MessagePack serialization** | Efficient with optional compression |
|
|
103
102
|
| **Zero-knowledge encryption** | Client-side AES-256-GCM |
|
|
104
|
-
| **Adaptive timeouts** | Auto-tune to system load |
|
|
105
103
|
|
|
106
104
|
---
|
|
107
105
|
|
|
@@ -220,7 +218,6 @@ def get_user_profile(user_id: int):
|
|
|
220
218
|
| Feature | `@cache.minimal` | `@cache.dev` | `@cache.test` | `@cache.production` | `@cache.secure` |
|
|
221
219
|
|:--------|:----------------:|:------------:|:-------------:|:-------------------:|:---------------:|
|
|
222
220
|
| Circuit Breaker | - | ✅ | - | ✅ | ✅ |
|
|
223
|
-
| Adaptive Timeouts | - | ✅ | - | ✅ | ✅ |
|
|
224
221
|
| Backpressure | ✅ | ✅ | - | ✅ | ✅ |
|
|
225
222
|
| Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
|
|
226
223
|
| Encryption | - | - | - | - | ✅ Required |
|
|
@@ -456,7 +453,6 @@ info = expensive_func.cache_info()
|
|
|
456
453
|
| [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
|
|
457
454
|
| [Prometheus Metrics][prometheus-url] | Built-in observability |
|
|
458
455
|
| [Zero-Knowledge Encryption][encryption-url] | Client-side security |
|
|
459
|
-
| [Adaptive Timeouts][adaptive-timeouts-url] | Auto-tune to infrastructure |
|
|
460
456
|
|
|
461
457
|
---
|
|
462
458
|
|
|
@@ -539,7 +535,6 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
539
535
|
[distributed-locking-url]: docs/features/distributed-locking.md
|
|
540
536
|
[prometheus-url]: docs/features/prometheus-metrics.md
|
|
541
537
|
[encryption-url]: docs/features/zero-knowledge-encryption.md
|
|
542
|
-
[adaptive-timeouts-url]: docs/features/adaptive-timeouts.md
|
|
543
538
|
[contributing-url]: CONTRIBUTING.md
|
|
544
539
|
[license-file-url]: LICENSE
|
|
545
540
|
[github-url]: https://github.com/cachekit-io/cachekit-py
|
|
@@ -47,7 +47,6 @@ That's it. You get:
|
|
|
47
47
|
| **Prometheus metrics** | Built-in observability |
|
|
48
48
|
| **MessagePack serialization** | Efficient with optional compression |
|
|
49
49
|
| **Zero-knowledge encryption** | Client-side AES-256-GCM |
|
|
50
|
-
| **Adaptive timeouts** | Auto-tune to system load |
|
|
51
50
|
|
|
52
51
|
---
|
|
53
52
|
|
|
@@ -166,7 +165,6 @@ def get_user_profile(user_id: int):
|
|
|
166
165
|
| Feature | `@cache.minimal` | `@cache.dev` | `@cache.test` | `@cache.production` | `@cache.secure` |
|
|
167
166
|
|:--------|:----------------:|:------------:|:-------------:|:-------------------:|:---------------:|
|
|
168
167
|
| Circuit Breaker | - | ✅ | - | ✅ | ✅ |
|
|
169
|
-
| Adaptive Timeouts | - | ✅ | - | ✅ | ✅ |
|
|
170
168
|
| Backpressure | ✅ | ✅ | - | ✅ | ✅ |
|
|
171
169
|
| Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
|
|
172
170
|
| Encryption | - | - | - | - | ✅ Required |
|
|
@@ -402,7 +400,6 @@ info = expensive_func.cache_info()
|
|
|
402
400
|
| [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
|
|
403
401
|
| [Prometheus Metrics][prometheus-url] | Built-in observability |
|
|
404
402
|
| [Zero-Knowledge Encryption][encryption-url] | Client-side security |
|
|
405
|
-
| [Adaptive Timeouts][adaptive-timeouts-url] | Auto-tune to infrastructure |
|
|
406
403
|
|
|
407
404
|
---
|
|
408
405
|
|
|
@@ -485,7 +482,6 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
485
482
|
[distributed-locking-url]: docs/features/distributed-locking.md
|
|
486
483
|
[prometheus-url]: docs/features/prometheus-metrics.md
|
|
487
484
|
[encryption-url]: docs/features/zero-knowledge-encryption.md
|
|
488
|
-
[adaptive-timeouts-url]: docs/features/adaptive-timeouts.md
|
|
489
485
|
[contributing-url]: CONTRIBUTING.md
|
|
490
486
|
[license-file-url]: LICENSE
|
|
491
487
|
[github-url]: https://github.com/cachekit-io/cachekit-py
|
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cachekit"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.16.0"
|
|
8
8
|
description = "Production-ready Redis caching for Python with intelligent reliability features and Rust-powered performance"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -57,8 +57,6 @@ dependencies = [
|
|
|
57
57
|
# Configuration and validation
|
|
58
58
|
"pydantic>=2.0.0",
|
|
59
59
|
"pydantic-settings>=2.0.0",
|
|
60
|
-
# Error handling
|
|
61
|
-
"tenacity>=8.0.0",
|
|
62
60
|
# Monitoring and observability
|
|
63
61
|
"prometheus-client>=0.22.1",
|
|
64
62
|
"psutil>=7.0.0",
|
|
@@ -47,7 +47,6 @@ That's it. You get:
|
|
|
47
47
|
| **Prometheus metrics** | Built-in observability |
|
|
48
48
|
| **MessagePack serialization** | Efficient with optional compression |
|
|
49
49
|
| **Zero-knowledge encryption** | Client-side AES-256-GCM |
|
|
50
|
-
| **Adaptive timeouts** | Auto-tune to system load |
|
|
51
50
|
|
|
52
51
|
---
|
|
53
52
|
|
|
@@ -166,7 +165,6 @@ def get_user_profile(user_id: int):
|
|
|
166
165
|
| Feature | `@cache.minimal` | `@cache.dev` | `@cache.test` | `@cache.production` | `@cache.secure` |
|
|
167
166
|
|:--------|:----------------:|:------------:|:-------------:|:-------------------:|:---------------:|
|
|
168
167
|
| Circuit Breaker | - | ✅ | - | ✅ | ✅ |
|
|
169
|
-
| Adaptive Timeouts | - | ✅ | - | ✅ | ✅ |
|
|
170
168
|
| Backpressure | ✅ | ✅ | - | ✅ | ✅ |
|
|
171
169
|
| Integrity Checking | - | ✅ | - | ✅ | ✅ 🔒 |
|
|
172
170
|
| Encryption | - | - | - | - | ✅ Required |
|
|
@@ -402,7 +400,6 @@ info = expensive_func.cache_info()
|
|
|
402
400
|
| [Distributed Locking][distributed-locking-url] | Cache stampede prevention |
|
|
403
401
|
| [Prometheus Metrics][prometheus-url] | Built-in observability |
|
|
404
402
|
| [Zero-Knowledge Encryption][encryption-url] | Client-side security |
|
|
405
|
-
| [Adaptive Timeouts][adaptive-timeouts-url] | Auto-tune to infrastructure |
|
|
406
403
|
|
|
407
404
|
---
|
|
408
405
|
|
|
@@ -485,7 +482,6 @@ MIT License - see [LICENSE][license-file-url] for details.
|
|
|
485
482
|
[distributed-locking-url]: docs/features/distributed-locking.md
|
|
486
483
|
[prometheus-url]: docs/features/prometheus-metrics.md
|
|
487
484
|
[encryption-url]: docs/features/zero-knowledge-encryption.md
|
|
488
|
-
[adaptive-timeouts-url]: docs/features/adaptive-timeouts.md
|
|
489
485
|
[contributing-url]: CONTRIBUTING.md
|
|
490
486
|
[license-file-url]: LICENSE
|
|
491
487
|
[github-url]: https://github.com/cachekit-io/cachekit-py
|
|
@@ -9,7 +9,6 @@ Supports pluggable backends: Redis (default), CachekitIO SaaS, File, and custom.
|
|
|
9
9
|
Key Features:
|
|
10
10
|
- **Intelligent @cache decorator** with auto-detection and intent-based optimization
|
|
11
11
|
- **Circuit breaker protection** against cascading failures
|
|
12
|
-
- **Adaptive timeout adjustment** based on historical backend latency patterns
|
|
13
12
|
- **Backpressure control** to prevent backend overload
|
|
14
13
|
- **Connection pooling** for optimized performance
|
|
15
14
|
- **Health check methods** for comprehensive monitoring
|
|
@@ -68,7 +67,7 @@ Example Usage:
|
|
|
68
67
|
```
|
|
69
68
|
"""
|
|
70
69
|
|
|
71
|
-
__version__ = "0.
|
|
70
|
+
__version__ = "0.16.0"
|
|
72
71
|
|
|
73
72
|
from collections.abc import Callable
|
|
74
73
|
from typing import Any, TypeVar
|
|
@@ -289,8 +289,8 @@ class TimeoutConfigurableBackend(Protocol):
|
|
|
289
289
|
"""Optional protocol for per-operation timeout configuration.
|
|
290
290
|
|
|
291
291
|
Backends implementing this protocol allow fine-grained timeout control
|
|
292
|
-
per operation
|
|
293
|
-
|
|
292
|
+
per operation, so a caller can set an explicit timeout for a single
|
|
293
|
+
operation where the backend supports it.
|
|
294
294
|
|
|
295
295
|
All backends support some timeout mechanism, but granularity varies:
|
|
296
296
|
- Per-operation: HTTP, DynamoDB, PostgreSQL
|
|
@@ -34,6 +34,7 @@ from cachekit.serializers.encryption_wrapper import DecryptionAuthenticationErro
|
|
|
34
34
|
from cachekit.serializers.wrapper import SerializationWrapper
|
|
35
35
|
|
|
36
36
|
if TYPE_CHECKING:
|
|
37
|
+
from cachekit.reliability.load_control import BackpressureController
|
|
37
38
|
from cachekit.serializers.base import SerializerProtocol
|
|
38
39
|
|
|
39
40
|
# Serializer string names whose wire format is language-agnostic and therefore safe to
|
|
@@ -1681,25 +1682,26 @@ class StandardCacheHandler:
|
|
|
1681
1682
|
def __init__(
|
|
1682
1683
|
self,
|
|
1683
1684
|
backend: BaseBackend,
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
ttl_refresh_threshold=0.5,
|
|
1685
|
+
backpressure_controller: BackpressureController | None = None,
|
|
1686
|
+
ttl_refresh_threshold: float = 0.5,
|
|
1687
1687
|
):
|
|
1688
1688
|
"""Initialize with backend and optional features.
|
|
1689
1689
|
|
|
1690
1690
|
Args:
|
|
1691
1691
|
backend: Backend instance (implements BaseBackend protocol)
|
|
1692
|
-
timeout_provider: Optional callable that returns timeout value
|
|
1693
1692
|
backpressure_controller: Optional BackpressureController for request limiting
|
|
1694
1693
|
ttl_refresh_threshold: Threshold for TTL refresh (0.0-1.0, default 0.5 = 50%)
|
|
1695
1694
|
"""
|
|
1696
1695
|
self.backend = backend
|
|
1697
|
-
self.timeout_provider = timeout_provider
|
|
1698
1696
|
self.backpressure_controller = backpressure_controller
|
|
1699
1697
|
self.ttl_refresh_threshold = ttl_refresh_threshold
|
|
1700
1698
|
|
|
1701
1699
|
def _with_backpressure_and_timeout(self, operation, *args, **kwargs):
|
|
1702
|
-
"""Execute operation
|
|
1700
|
+
"""Execute operation under backpressure control.
|
|
1701
|
+
|
|
1702
|
+
Operation timeouts are enforced at the backend connection layer
|
|
1703
|
+
(e.g. redis-py socket_timeout), not here.
|
|
1704
|
+
"""
|
|
1703
1705
|
if self.backpressure_controller:
|
|
1704
1706
|
# Apply backpressure control first
|
|
1705
1707
|
with self.backpressure_controller.acquire():
|
|
@@ -17,7 +17,6 @@ from .nested import (
|
|
|
17
17
|
EncryptionConfig,
|
|
18
18
|
L1CacheConfig,
|
|
19
19
|
MonitoringConfig,
|
|
20
|
-
TimeoutConfig,
|
|
21
20
|
)
|
|
22
21
|
from .settings import CachekitConfig
|
|
23
22
|
|
|
@@ -37,7 +36,6 @@ __all__ = [
|
|
|
37
36
|
"EncryptionConfig",
|
|
38
37
|
"L1CacheConfig",
|
|
39
38
|
"MonitoringConfig",
|
|
40
|
-
"TimeoutConfig",
|
|
41
39
|
# Backend management
|
|
42
40
|
"set_default_backend",
|
|
43
41
|
"get_default_backend",
|
|
@@ -17,7 +17,6 @@ from .nested import (
|
|
|
17
17
|
EncryptionConfig,
|
|
18
18
|
L1CacheConfig,
|
|
19
19
|
MonitoringConfig,
|
|
20
|
-
TimeoutConfig,
|
|
21
20
|
)
|
|
22
21
|
from .validation import ConfigurationError
|
|
23
22
|
|
|
@@ -180,7 +179,6 @@ class DecoratorConfig:
|
|
|
180
179
|
backend: L2 backend (RedisBackend, HTTPBackend, None for L1-only)
|
|
181
180
|
l1: L1 in-memory cache configuration
|
|
182
181
|
circuit_breaker: Circuit breaker configuration
|
|
183
|
-
timeout: Adaptive timeout configuration
|
|
184
182
|
backpressure: Backpressure configuration
|
|
185
183
|
monitoring: Monitoring and observability configuration
|
|
186
184
|
encryption: Client-side encryption configuration
|
|
@@ -212,10 +210,9 @@ class DecoratorConfig:
|
|
|
212
210
|
# Backend abstraction (1 field)
|
|
213
211
|
backend: BaseBackend | None = None # L2 backend: RedisBackend, HTTPBackend (future), None (L1-only)
|
|
214
212
|
|
|
215
|
-
# Nested configuration groups (
|
|
213
|
+
# Nested configuration groups (5 groups)
|
|
216
214
|
l1: L1CacheConfig = field(default_factory=L1CacheConfig)
|
|
217
215
|
circuit_breaker: CircuitBreakerConfig = field(default_factory=CircuitBreakerConfig)
|
|
218
|
-
timeout: TimeoutConfig = field(default_factory=TimeoutConfig)
|
|
219
216
|
backpressure: BackpressureConfig = field(default_factory=BackpressureConfig)
|
|
220
217
|
monitoring: MonitoringConfig = field(default_factory=MonitoringConfig)
|
|
221
218
|
encryption: EncryptionConfig = field(default_factory=EncryptionConfig)
|
|
@@ -264,7 +261,6 @@ class DecoratorConfig:
|
|
|
264
261
|
# Validate nested configs
|
|
265
262
|
self.l1.validate()
|
|
266
263
|
self.circuit_breaker.validate()
|
|
267
|
-
self.timeout.validate()
|
|
268
264
|
self.backpressure.validate()
|
|
269
265
|
self.monitoring.validate()
|
|
270
266
|
self.encryption.validate()
|
|
@@ -296,13 +292,6 @@ class DecoratorConfig:
|
|
|
296
292
|
"recovery_timeout": self.circuit_breaker.recovery_timeout,
|
|
297
293
|
"half_open_requests": self.circuit_breaker.half_open_requests,
|
|
298
294
|
"excluded_exceptions": self.circuit_breaker.excluded_exceptions,
|
|
299
|
-
# Timeout (flattened)
|
|
300
|
-
"adaptive_timeout": self.timeout.enabled,
|
|
301
|
-
"initial_timeout": self.timeout.initial,
|
|
302
|
-
"min_timeout": self.timeout.min,
|
|
303
|
-
"max_timeout": self.timeout.max,
|
|
304
|
-
"timeout_window_size": self.timeout.window_size,
|
|
305
|
-
"timeout_percentile": self.timeout.percentile,
|
|
306
295
|
# Backpressure (flattened)
|
|
307
296
|
"backpressure": self.backpressure.enabled,
|
|
308
297
|
"max_concurrent_requests": self.backpressure.max_concurrent_requests,
|
|
@@ -326,7 +315,7 @@ class DecoratorConfig:
|
|
|
326
315
|
"""Minimal protections profile: Maximum throughput, minimal overhead.
|
|
327
316
|
|
|
328
317
|
Use cases: Read-heavy workloads, non-critical caching, high-performance scenarios
|
|
329
|
-
Trade-offs: Circuit breaker disabled,
|
|
318
|
+
Trade-offs: Circuit breaker disabled, no monitoring, NO integrity checking
|
|
330
319
|
|
|
331
320
|
Note: Backend resolved from REDIS_URL env var, set_default_backend(), or explicit backend= kwarg
|
|
332
321
|
|
|
@@ -348,11 +337,9 @@ class DecoratorConfig:
|
|
|
348
337
|
l1=L1CacheConfig(
|
|
349
338
|
enabled=True,
|
|
350
339
|
swr_enabled=False,
|
|
351
|
-
invalidation_enabled=False,
|
|
352
340
|
namespace_index=False,
|
|
353
341
|
),
|
|
354
342
|
circuit_breaker=CircuitBreakerConfig(enabled=False),
|
|
355
|
-
timeout=TimeoutConfig(enabled=False),
|
|
356
343
|
backpressure=BackpressureConfig(enabled=True),
|
|
357
344
|
monitoring=MonitoringConfig(
|
|
358
345
|
collect_stats=False,
|
|
@@ -368,7 +355,7 @@ class DecoratorConfig:
|
|
|
368
355
|
"""Production profile: All protections enabled, full observability, integrity checking ON.
|
|
369
356
|
|
|
370
357
|
Use cases: Payment systems, APIs, production services, critical workloads
|
|
371
|
-
Trade-offs: Additional latency from circuit breaker,
|
|
358
|
+
Trade-offs: Additional latency from circuit breaker, monitoring, integrity validation
|
|
372
359
|
|
|
373
360
|
Note: Backend resolved from REDIS_URL env var, set_default_backend(), or explicit backend= kwarg
|
|
374
361
|
|
|
@@ -390,11 +377,9 @@ class DecoratorConfig:
|
|
|
390
377
|
l1=L1CacheConfig(
|
|
391
378
|
enabled=True,
|
|
392
379
|
swr_enabled=True,
|
|
393
|
-
invalidation_enabled=True,
|
|
394
380
|
namespace_index=True,
|
|
395
381
|
),
|
|
396
382
|
circuit_breaker=CircuitBreakerConfig(enabled=True),
|
|
397
|
-
timeout=TimeoutConfig(enabled=True),
|
|
398
383
|
backpressure=BackpressureConfig(enabled=True),
|
|
399
384
|
monitoring=MonitoringConfig(
|
|
400
385
|
collect_stats=True,
|
|
@@ -457,7 +442,6 @@ class DecoratorConfig:
|
|
|
457
442
|
l1=L1CacheConfig(
|
|
458
443
|
enabled=True, # L1 stores encrypted bytes. Enabled: ~50ns hits vs 2-7ms Redis
|
|
459
444
|
swr_enabled=True,
|
|
460
|
-
invalidation_enabled=True,
|
|
461
445
|
namespace_index=True,
|
|
462
446
|
),
|
|
463
447
|
encryption=EncryptionConfig(
|
|
@@ -469,7 +453,6 @@ class DecoratorConfig:
|
|
|
469
453
|
fail_closed=fail_closed,
|
|
470
454
|
),
|
|
471
455
|
circuit_breaker=CircuitBreakerConfig(enabled=True),
|
|
472
|
-
timeout=TimeoutConfig(enabled=True),
|
|
473
456
|
backpressure=BackpressureConfig(enabled=True),
|
|
474
457
|
monitoring=MonitoringConfig(
|
|
475
458
|
collect_stats=True,
|
|
@@ -507,11 +490,9 @@ class DecoratorConfig:
|
|
|
507
490
|
l1=L1CacheConfig(
|
|
508
491
|
enabled=True,
|
|
509
492
|
swr_enabled=True,
|
|
510
|
-
invalidation_enabled=False,
|
|
511
493
|
namespace_index=False,
|
|
512
494
|
),
|
|
513
495
|
circuit_breaker=CircuitBreakerConfig(enabled=True),
|
|
514
|
-
timeout=TimeoutConfig(enabled=True),
|
|
515
496
|
backpressure=BackpressureConfig(enabled=True),
|
|
516
497
|
monitoring=MonitoringConfig(
|
|
517
498
|
collect_stats=True,
|
|
@@ -527,7 +508,7 @@ class DecoratorConfig:
|
|
|
527
508
|
"""Testing profile: Deterministic, all protections disabled, no monitoring, no integrity checking.
|
|
528
509
|
|
|
529
510
|
Use cases: Unit tests, integration tests (with fakeredis)
|
|
530
|
-
Trade-offs: No circuit breaker, no
|
|
511
|
+
Trade-offs: No circuit breaker, no stats, no integrity (reproducible, fast)
|
|
531
512
|
|
|
532
513
|
Note: Backend resolved from REDIS_URL env var, set_default_backend(), or explicit backend= kwarg
|
|
533
514
|
|
|
@@ -549,11 +530,9 @@ class DecoratorConfig:
|
|
|
549
530
|
l1=L1CacheConfig(
|
|
550
531
|
enabled=True,
|
|
551
532
|
swr_enabled=False,
|
|
552
|
-
invalidation_enabled=False,
|
|
553
533
|
namespace_index=False,
|
|
554
534
|
),
|
|
555
535
|
circuit_breaker=CircuitBreakerConfig(enabled=False),
|
|
556
|
-
timeout=TimeoutConfig(enabled=False),
|
|
557
536
|
backpressure=BackpressureConfig(enabled=False),
|
|
558
537
|
monitoring=MonitoringConfig(
|
|
559
538
|
collect_stats=False,
|
|
@@ -624,11 +603,9 @@ class DecoratorConfig:
|
|
|
624
603
|
l1=L1CacheConfig(
|
|
625
604
|
enabled=True,
|
|
626
605
|
swr_enabled=True,
|
|
627
|
-
invalidation_enabled=True,
|
|
628
606
|
namespace_index=True,
|
|
629
607
|
),
|
|
630
608
|
circuit_breaker=CircuitBreakerConfig(enabled=True),
|
|
631
|
-
timeout=TimeoutConfig(enabled=True),
|
|
632
609
|
backpressure=BackpressureConfig(enabled=True),
|
|
633
610
|
monitoring=MonitoringConfig(
|
|
634
611
|
collect_stats=True,
|
|
@@ -30,7 +30,6 @@ class L1CacheConfig:
|
|
|
30
30
|
task and sync functions via a daemon thread.
|
|
31
31
|
swr_threshold_ratio: Fraction of TTL after which a hit triggers a background
|
|
32
32
|
refresh, in (0.0, 1.0] (default: 0.5)
|
|
33
|
-
invalidation_enabled: Enable invalidation event broadcasts (default: True)
|
|
34
33
|
namespace_index: Enable fast namespace-based invalidation (default: True)
|
|
35
34
|
|
|
36
35
|
Examples:
|
|
@@ -59,7 +58,6 @@ class L1CacheConfig:
|
|
|
59
58
|
max_size_mb: int | None = None
|
|
60
59
|
swr_enabled: bool = True
|
|
61
60
|
swr_threshold_ratio: float = 0.5
|
|
62
|
-
invalidation_enabled: bool = True
|
|
63
61
|
namespace_index: bool = True
|
|
64
62
|
|
|
65
63
|
def validate(self) -> None:
|
|
@@ -135,64 +133,6 @@ class CircuitBreakerConfig:
|
|
|
135
133
|
raise ConfigurationError(f"half_open_requests must be >= 1, got {self.half_open_requests}")
|
|
136
134
|
|
|
137
135
|
|
|
138
|
-
@dataclass(frozen=True)
|
|
139
|
-
class TimeoutConfig:
|
|
140
|
-
"""Adaptive timeout configuration.
|
|
141
|
-
|
|
142
|
-
Adaptive timeout dynamically adjusts request timeouts based on observed
|
|
143
|
-
latency percentiles, preventing both premature timeouts and excessive waiting.
|
|
144
|
-
|
|
145
|
-
Attributes:
|
|
146
|
-
enabled: Enable adaptive timeout (default: True)
|
|
147
|
-
initial: Initial timeout in seconds (default: 1.0)
|
|
148
|
-
min: Minimum timeout in seconds (default: 0.1)
|
|
149
|
-
max: Maximum timeout in seconds (default: 5.0)
|
|
150
|
-
window_size: Number of requests in sliding window for percentile calculation (default: 1000)
|
|
151
|
-
percentile: Target percentile for timeout calculation (default: 95.0)
|
|
152
|
-
|
|
153
|
-
Examples:
|
|
154
|
-
Create with defaults:
|
|
155
|
-
|
|
156
|
-
>>> config = TimeoutConfig()
|
|
157
|
-
>>> config.initial
|
|
158
|
-
1.0
|
|
159
|
-
>>> config.min
|
|
160
|
-
0.1
|
|
161
|
-
>>> config.max
|
|
162
|
-
5.0
|
|
163
|
-
|
|
164
|
-
Custom timeout range:
|
|
165
|
-
|
|
166
|
-
>>> custom = TimeoutConfig(min=0.5, initial=2.0, max=10.0)
|
|
167
|
-
>>> custom.validate() # No error = valid
|
|
168
|
-
|
|
169
|
-
Invalid range (initial must be between min and max):
|
|
170
|
-
|
|
171
|
-
>>> TimeoutConfig(min=1.0, initial=0.5, max=5.0).validate() # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
172
|
-
Traceback (most recent call last):
|
|
173
|
-
...
|
|
174
|
-
cachekit.config.validation.ConfigurationError: Timeout must satisfy: min (1.0) <= initial (0.5) <= max (5.0)
|
|
175
|
-
"""
|
|
176
|
-
|
|
177
|
-
enabled: bool = True
|
|
178
|
-
initial: float = 1.0
|
|
179
|
-
min: float = 0.1
|
|
180
|
-
max: float = 5.0
|
|
181
|
-
window_size: int = 1000
|
|
182
|
-
percentile: float = 95.0
|
|
183
|
-
|
|
184
|
-
def validate(self) -> None:
|
|
185
|
-
"""Validate adaptive timeout configuration.
|
|
186
|
-
|
|
187
|
-
Raises:
|
|
188
|
-
ConfigurationError: If timeout values are inconsistent
|
|
189
|
-
"""
|
|
190
|
-
if not self.min <= self.initial <= self.max:
|
|
191
|
-
raise ConfigurationError(f"Timeout must satisfy: min ({self.min}) <= initial ({self.initial}) <= max ({self.max})")
|
|
192
|
-
if not 0.0 < self.percentile <= 100.0:
|
|
193
|
-
raise ConfigurationError(f"percentile must be 0.0-100.0, got {self.percentile}")
|
|
194
|
-
|
|
195
|
-
|
|
196
136
|
@dataclass(frozen=True)
|
|
197
137
|
class BackpressureConfig:
|
|
198
138
|
"""Backpressure configuration for overload protection.
|
|
@@ -66,8 +66,6 @@ def cache(
|
|
|
66
66
|
>>> config = DecoratorConfig.production(ttl=600, backend=None)
|
|
67
67
|
>>> config.circuit_breaker.enabled
|
|
68
68
|
True
|
|
69
|
-
>>> config.timeout.enabled
|
|
70
|
-
True
|
|
71
69
|
|
|
72
70
|
Intent-based secure (security-critical with encryption):
|
|
73
71
|
>>> config = DecoratorConfig.secure(
|
|
@@ -8,7 +8,6 @@ from ..monitoring.pool_monitor import OptimizedPoolMonitor
|
|
|
8
8
|
|
|
9
9
|
# Import EXISTING modules - no duplication
|
|
10
10
|
from ..reliability import (
|
|
11
|
-
AdaptiveTimeout,
|
|
12
11
|
AsyncMetricsCollector,
|
|
13
12
|
BackpressureController,
|
|
14
13
|
CircuitBreaker,
|
|
@@ -29,7 +28,6 @@ class FeatureOrchestrator:
|
|
|
29
28
|
>>> orch = FeatureOrchestrator(
|
|
30
29
|
... namespace="test",
|
|
31
30
|
... circuit_breaker_enabled=False,
|
|
32
|
-
... adaptive_timeout_enabled=False,
|
|
33
31
|
... backpressure_enabled=False,
|
|
34
32
|
... )
|
|
35
33
|
>>> orch.namespace
|
|
@@ -60,24 +58,20 @@ class FeatureOrchestrator:
|
|
|
60
58
|
self,
|
|
61
59
|
namespace: str,
|
|
62
60
|
circuit_breaker_enabled: bool = True,
|
|
63
|
-
adaptive_timeout_enabled: bool = True,
|
|
64
61
|
backpressure_enabled: bool = True,
|
|
65
62
|
collect_stats: bool = True,
|
|
66
63
|
enable_structured_logging: bool = True,
|
|
67
64
|
circuit_breaker_config: Optional[dict[str, Any]] = None,
|
|
68
|
-
adaptive_timeout_config: Optional[dict[str, Any]] = None,
|
|
69
65
|
backpressure_config: Optional[dict[str, Any]] = None,
|
|
70
66
|
):
|
|
71
67
|
self.namespace = namespace
|
|
72
68
|
self._circuit_breaker_enabled = circuit_breaker_enabled
|
|
73
|
-
self._adaptive_timeout_enabled = adaptive_timeout_enabled
|
|
74
69
|
self._backpressure_enabled = backpressure_enabled
|
|
75
70
|
self._collect_stats = collect_stats
|
|
76
71
|
self._enable_structured_logging = enable_structured_logging
|
|
77
72
|
|
|
78
73
|
# Initialize EXISTING modules
|
|
79
74
|
self._circuit_breaker = None
|
|
80
|
-
self._adaptive_timeout = None
|
|
81
75
|
self._load_control = None
|
|
82
76
|
self._metrics_collector = None
|
|
83
77
|
self._correlation_tracker = None
|
|
@@ -99,9 +93,6 @@ class FeatureOrchestrator:
|
|
|
99
93
|
# Already a CircuitBreakerConfig object
|
|
100
94
|
self._circuit_breaker = CircuitBreaker(config=circuit_breaker_config, namespace=namespace)
|
|
101
95
|
|
|
102
|
-
if adaptive_timeout_enabled:
|
|
103
|
-
self._adaptive_timeout = AdaptiveTimeout(**(adaptive_timeout_config or {}))
|
|
104
|
-
|
|
105
96
|
if backpressure_enabled:
|
|
106
97
|
self._load_control = BackpressureController(**(backpressure_config or {}))
|
|
107
98
|
|
|
@@ -119,11 +110,6 @@ class FeatureOrchestrator:
|
|
|
119
110
|
"""Get circuit breaker if enabled."""
|
|
120
111
|
return self._circuit_breaker
|
|
121
112
|
|
|
122
|
-
@property
|
|
123
|
-
def adaptive_timeout(self) -> Optional[AdaptiveTimeout]:
|
|
124
|
-
"""Get adaptive timeout if enabled."""
|
|
125
|
-
return self._adaptive_timeout
|
|
126
|
-
|
|
127
113
|
@property
|
|
128
114
|
def load_control(self) -> Optional[BackpressureController]:
|
|
129
115
|
"""Get load control if enabled."""
|
|
@@ -170,15 +156,6 @@ class FeatureOrchestrator:
|
|
|
170
156
|
# For now, always return True and let acquire handle backpressure
|
|
171
157
|
return True
|
|
172
158
|
|
|
173
|
-
def get_timeout(self, operation_type: str = "default") -> float:
|
|
174
|
-
"""Get current timeout for operation type."""
|
|
175
|
-
# Guard clause: No adaptive timeout means use default
|
|
176
|
-
if not self._adaptive_timeout:
|
|
177
|
-
return 5.0 # Default timeout
|
|
178
|
-
|
|
179
|
-
# AdaptiveTimeout.get_timeout() doesn't take arguments
|
|
180
|
-
return self._adaptive_timeout.get_timeout()
|
|
181
|
-
|
|
182
159
|
def start_request(self) -> Optional[str]:
|
|
183
160
|
"""Start request tracking."""
|
|
184
161
|
# Note: BackpressureController uses acquire() context manager, not start_request()
|
|
@@ -399,26 +376,6 @@ class FeatureOrchestrator:
|
|
|
399
376
|
hit=hit,
|
|
400
377
|
)
|
|
401
378
|
|
|
402
|
-
def record_duration(self, duration: float):
|
|
403
|
-
"""Record operation duration."""
|
|
404
|
-
# AdaptiveTimeout doesn't have record_success method, just skip for now
|
|
405
|
-
pass
|
|
406
|
-
|
|
407
|
-
def get_adaptive_lock_timeouts(self):
|
|
408
|
-
"""Get adaptive lock timeouts if available."""
|
|
409
|
-
return None # Return None to use defaults
|
|
410
|
-
|
|
411
|
-
def record_lock_operation(self, duration: float, success: bool):
|
|
412
|
-
"""Record lock operation performance."""
|
|
413
|
-
if self._metrics_collector:
|
|
414
|
-
self._metrics_collector.record_cache_operation(
|
|
415
|
-
operation="lock",
|
|
416
|
-
namespace=self.namespace,
|
|
417
|
-
serializer="rust",
|
|
418
|
-
success=success,
|
|
419
|
-
duration_ms=duration * 1000,
|
|
420
|
-
)
|
|
421
|
-
|
|
422
379
|
def check_health(self) -> dict[str, Any]:
|
|
423
380
|
"""Check health status - returns simplified status format."""
|
|
424
381
|
full_status = self.get_health_status()
|