Skip to content

More 0.2.0 features: stale-while-revalidate, cache stores, retry budget, periodic, OpenTelemetry, pickling - #6

Merged
Pythondeveloper6 merged 27 commits into
mainfrom
feat/v0.2-extras
Oct 29, 2026
Merged

Pythondeveloper6 merged 27 commits into
mainfrom
feat/v0.2-extras

Conversation

@Pythondeveloper6

Copy link
Copy Markdown
Collaborator

Adds to the unreleased 0.2.0:

  • memoize: stale_ttl (stale-while-revalidate), store= with the CacheStore protocol, per_instance=True (weakly held per-instance method caches); async hits about 35% faster.
  • retry: RetryBudget shared across functions, retry_if_result=, async retry_if/on_retry/result predicates, async with attempt in retrying.
  • periodic: drift-free background loop for sync and async functions with clean start/stop.
  • trace(otel=True): optional OpenTelemetry spans (lazy import, still zero runtime dependencies).
  • timeout(cleanup_grace=): bounded async cleanup after the limit.
  • Decorated functions pickle by reference (ProcessPoolExecutor with spawn); stateful objects refuse pickling with a clear error.
  • CI: tests and the thread-safety stress suite on free-threaded Python 3.14t.
  • Docs links now point at pythonwrap.readthedocs.io (the old domain returned 404); mkdocstrings upgraded to 1.x with its companions (supersedes deps: update mkdocstrings[python] requirement from >=0.27 to >=1.0.6 in the dev-tooling group across 1 directory #3).
  • Fixes from an independent review of the new code (cancellation handling in periodic.stop and cleanup_grace).

Local checks: 992 tests on 3.12-3.14 and 3.14t (986 on 3.10/3.11), stress suite on 3.14t, mypy strict, ruff, 210 doc examples, strict docs build, twine check.

RetryBudget caps retries at a fraction of traffic, shared across functions,
threads and event loops; retry/retrying accept budget= (also configurable via
configure(retry={"budget": ...})). retry_if_result retries on bad return
values and returns the last value when retries run out. Async functions accept
async retry_if, retry_if_result and on_retry; sync functions reject them at
decoration time. New event: retry.budget_exhausted.
…to memoize

memoize(ttl=..., stale_ttl=...) serves a stale value while one background
refresh runs (a task for async functions, a daemon thread for sync ones).
memoize(store=...) keeps entries in any CacheStore. memoize(per_instance=True)
caches methods per instance through weak references, so instances stay
collectable and need not be hashable. New events cache.stale and
cache.refresh_failed.
Periodic and AsyncPeriodic objects now pickle by module and qualified name, so
every decorated module-level function can be sent to a spawn-context process
pool. CircuitBreaker, RateLimiter, Bulkhead, RetryBudget, Transaction, Policy
and FakeClock raise a clear TypeError when pickled or copied, since their state
belongs to one process. Adds tests/test_pickling.py and a docs section.
- AsyncPeriodic.stop() no longer swallows a cancellation aimed at its caller
- stop() from inside an async run ends the loop without waiting a tick
- timeout(cleanup_grace=) keeps outside cancellations as CancelledError and
  waits for and consumes the child task when the caller is cancelled
- log an on_error="raise" error that a restart would otherwise drop
- document cleanup_grace contextvars and disable_retries budget deposits
@Pythondeveloper6
Pythondeveloper6 merged commit 8be39bc into main Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant