chore(main): release 0.20.0 - #332
cachekit-release-bot[bot] wants to merge 2 commits into
Conversation
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Repository: cachekit-io/cachekit-py/.coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
Kody Code Review — 1 suggested fix. 🛠️ Open Agent Prompt |
85e1699 to
2e55b84
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
2e55b84 to
f81a188
Compare
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
970ed63 to
b16924f
Compare
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
a67413f to
830b0a4
Compare
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
5b07c23
64431bc to
5b07c23
Compare
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
1bc7a34 to
7805d39
Compare
Code Review Completed! 🔥The code review was successfully completed based on your current configurations. Kody Guide: Usage and ConfigurationInteracting with Kody
Providing Context (Files & MCPs)Add these hints in your PR description (or a comment) to unlock deeper checks:
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
ccaa9be
f4962fc to
ccaa9be
Compare
5b633c2 to
a884f95
Compare
76d3562 to
dc60d9c
Compare
🤖 I have created a release beep boop
0.20.0 (2026-09-29)
⚠ BREAKING CHANGES
FeatureOrchestrator(exported fromcachekit.decorators.__all__) no longer definesgenerate_correlation_id,create_correlation_id,set_correlation_id,clear_correlation_id,start_request,end_request, or thecorrelation_trackerproperty.FeatureOrchestrator.handle_cache_errorno longer accepts acorrelation_idkeyword argument. An explicit caller passingcorrelation_id=now flows it through**extra_context, and its log record is unchanged. The decorator's own*_failederror records no longer carry acorrelation_idkey; that value was a per-call UUID, orNone, and nothing read it.src/cachekit/monitoring/correlation_tracking.py(CorrelationTracker,LoggerIntegratedTracker, module-levelgenerate_correlation_id/set_correlation_id/get_correlation_id/clear_correlation_id/correlation_context) is removed entirely.AsyncMetricsCollector.record_cache_operation()andFeatureOrchestrator.record_cache_operation()no longer accepthit. Callers that pass it now raiseTypeError.FeatureOrchestrator.record_success()no longer emits a metrics record.nsornsapias an interop namespace on Redis, Memcached or File backends worked before this change and must now rename the namespace. Renaming means a full cache miss for that namespace.default), purge the Redis entries that earlier releases wrote. In earlier releases a decorated function that resolved Redis from the environment (CACHEKIT_REDIS_URL,REDIS_URLor the localhost default), or a backend taken fromRedisBackendProvider.get_backend(), stayed bound to the tenant current when that backend was first obtained, so every tenant's L2 writes through it landed under that one tenant'st:<tenant>:prefix. That tenant keeps reading those entries as its own after the upgrade, and some hold another tenant's value. Entries written withttl=None, or kept alive byrefresh_ttl_on_get=True, never expire, and a no-argumentinvalidate_cache()reaches only those the calling tenant has read in that process since it started, because no key registry recorded them. After the last process running an earlier release has stopped, delete everyt:*key in each database cachekit uses. Run this with the Python that cachekit is installed in, since it uses cachekit's redis-py dependency; it prints0 keys leftwhen it is done:python -c 'import itertools, sys, redis; r = redis.Redis.from_url(sys.argv[1]); keys = r.scan_iter(match=sys.argv[2], count=1000); [r.unlink(*b) for b in iter(lambda: list(itertools.islice(keys, 1000)), [])]; print(sum(1 for _ in r.scan_iter(match=sys.argv[2], count=1000)), "keys left")' '<redis-url>' 't:*'. Do not use aredis-cli --scanpipeline: a key set throughkey=can contain a newline or a NUL byte, which the pipeline turns into names that match nothing, so the key survives and the pipeline still exits 0. RunFLUSHDBinstead only if that database is dedicated to cachekit. Then restart every process, because L1 keeps any entry a process read before the purge for up to the function'sttl(300 s withttl=None), and expect a cold cache. On a shared databaset:*also matches any other application's keys that start witht:, so run the same command with't:<tenant>:*'in place of't:*'fordefaultand for each tenant you have set, the tenant percent-encoded withurllib.parse.quote(tenant, safe=''), anintorUUIDtenant as itsstr()first (tenantorg:123is't:org%3A123:*'). A deployment that only ever used one tenant is unaffected.RedisBackendProvider.get_backend()no longer binds its backend to one tenant: the backend followstenant_contexton every operation and falls back to the tenant current at theget_backend()call only when the calling context has none; for a backend bound to one tenant, constructcachekit.backends.redis.provider.PerRequestRedisBackend(client, tenant)directly, withclientaredis.Redis. A no-argumentinvalidate_cache()on the Redis backend now deletes only the calling tenant's L2 entries. Settenant_contextonly to astr,bytes,intoruuid.UUID: the Redis backend checks each operation's tenant and raisesTypeErrorfor any other type, including abool, anIntEnummember and abytearray, so convert anIntEnummember withint()and abytearraywithbytes()first.intandUUIDtenants now work, keyed by theirstr()form (42and"42"sharet:42:), which no earlier release did.cachekit.logging.JsonFormatteris removed; importing it now raises ImportError.StructuredLogger.circuit_breaker_state_changeandStructuredLogger.set_correlation_idare removed and now raise AttributeError. No deprecation aliases. Useset_trace_id/clear_trace_id(orcachekit.monitoring.correlation_tracking) for request correlation, and your ownlogging.Formattersubclass for JSON output.serializer="auto","orjson","arrow", or any serializer passed as an instance was writing:1skeys and will now write:1a,:1o,:1wor anx-prefixed code. That function's entire working set recomputes once at deploy, so plan a cold cache or roll out behind existing warm-up / stampede controls. Deployments on the default serializer are unaffected: their keys were already:1sand stay:1s. Orphaned entries are also a retention question, not only a hit-rate one: once the key changes,invalidate_cache()computes the new key and can no longer reach the old copy, so a deletion for erasure, consent withdrawal or permission revocation reports success while the pre-upgrade entry survives to its TTL — or indefinitely wherettl=None. Flush the affected namespaces on upgrade if you cache personal data rather than relying on expiry.CachekitIOBackend(...)configuration errors (missing, empty or whitespace-containing API key; invalid API URL) now raisecachekit.config.ConfigurationErrorat construction instead ofValueErroror pydanticValidationError, so code catchingValueErrorthere must catchConfigurationError.@cache.io(backend=...)and@cache.io(config=...)now raiseConfigurationErrorinstead of silently ignoring the argument. Underset_default_backend(),@cache(config=...)now uses the backend insideconfig=instead of the module default.cachekit.backends.cachekitio.client.get_sync_http_client()is replaced bylease_sync_http_client(), which returns aSyncClientLease: hold the lease for as long as its.clientis used, because the client is closed when the lease is dropped.Features
Bug Fixes
Code Refactoring
This PR was generated with Release Please. See documentation.