Skip to content

Releases: jolovicdev/cashet

Release 0.4.4: async tasks, nested refs, and hash correctness (#22)

11 May 01:05
5d19078

Choose a tag to compare

  • Fix: AsyncClient now awaits async def task functions correctly.
  • Fix: function hashes include immutable globals used by nested code objects, plus stable built-ins like range, slice, and datetime values.
  • Fix: nested ResultRef / AsyncResultRef values resolve inside containers and input refs are deduplicated in commit metadata.
  • Fix: nested ref resolution preserves tuple subclasses and avoids invalid dict/frozenset containers from unhashable resolved values.
  • Fix: task functions returning awaitable objects keep those objects as the actual cached result.
  • Fix: base installs raise a clear cashet[redis] extra error when Redis backends are imported without Redis dependencies.

Release 0.4.3: hotfix freezegun dep, Redis race guard, flaky heartbeat test (#8)

01 May 16:52

Choose a tag to compare

  • Fix: add freezegun to dev dependencies — TTL/GC tests no longer fail with ModuleNotFoundError on fresh installs or CI.
  • Fix: restore expires_at <= now race guard in Redis find_by_fingerprint — a commit can expire between the ZREVRANGEBYSCORE server-side filter and the get_commit call.
  • Fix: bump heartbeat test running_ttl from 100ms to 3s — 100ms is too tight for CI runners, causing sporadic stale claim reclamation.

Release 0.4.2: tag-index invalidation perf, Redis TTL pushdown, invalidate CLI (#7)

01 May 16:34

Choose a tag to compare

  • Perf: delete_by_tags in SQLite batches all matching rows into a single DELETE with one orphan-detection pass — previously O(n) row-by-row calls with per-row orphan queries.
  • Perf: delete_by_tags in Redis now uses tag-set indexes (cashet:tag:{key}, cashet:tag:{key}:{value}) with SINTER — previously a full zrevrange(all) scan fetching every commit.
  • Perf: find_by_fingerprint in Redis pushes TTL filtering server-side via ZREVRANGEBYSCORE using expires_at timestamp as the sorted-set score — previously Python-iterated all candidates checking expires_at client-side.
  • Feat: cashet invalidate -t key=value / -t key CLI command.
  • Test: replaced time.sleep with freezegun in 3 TTL/GC tests for deterministic execution.
  • Test: added Redis delete_by_tags coverage (exact match, bare key, multi-condition) and CLI invalidate tests.

Release 0.4.1: hash prefix fix, TTL perf, and test coverage (#6)

01 May 16:00

Choose a tag to compare

  • Fix: hash prefix lookups normalized to lowercase — uppercase hex chars (A-F) no longer fail to match SHA-256 digests.
  • Fix: idx_last_accessed_at creation moved after the column migration — opening a pre-migration database no longer crashes with "no such column".
  • Perf: TTL expiration filter pushed into SQL WHERE clause instead of O(n) Python iteration.
  • Test: ambiguous prefix delete_commit rollback verified to not poison subsequent writes.
  • Test: TTL coverage for submit_many list and dict paths, including re-execution after expiry.
  • Docs: CHANGELOG.md added, covering all versions back to 0.1.1.

Release 0.4.0

30 Apr 20:34
8b10a91

Choose a tag to compare

Fixed

  • Hash prefix validation — prevents *, ?, _ from reaching SQL LIKE and Redis glob patterns
  • Stale claim sync — reclaims now copy current cache, force, timeout, tags instead of stale config
  • SQLite schema migrations — forward-migrates force and timeout_seconds columns safely
  • Delete rollback — early returns in delete_commit() no longer leave dangling transactions
  • Import integrityimport_archive() now SHA-256-verifies blobs before writing

New

  • Per-entry TTLsubmit(_ttl=...), @client.task(ttl=...), auto-expiry via Commit.expires_at
  • Tag-based invalidationclient.invalidate(tags={...}) deletes matching commits atomically
  • TTL-aware lookupsfind_by_fingerprint() and get_history() skip expired commits

Tests: 325 passed. Ruff clean. Pyright clean.

Release v0.3.2

29 Apr 22:32
3bafb35

Choose a tag to compare

What's Changed

Full Changelog: v0.3.1...v0.3.2

0.3.1

28 Apr 16:48
3a6a436

Choose a tag to compare

Core Architecture

  • Extract shared client base (_client_base.py), async runner (_runner.py), and sync store adapter (adapters.py)
  • Unify batch execution and executor paths between sync and async clients

Store Backends

  • SQLite: Deduped file locks per path with _SQLiteLockState to prevent lock churn
  • Redis: O(1) blob stats via maintained counters instead of O(n) scans
  • Redis: Atomic Lua script for orphan cleanup with stats decrement
  • Redis: Eviction backfills partial last_accessed index before removing old commits
  • Redis: put_commit ref-count race fixed with WATCH/MULTI/EXEC optimistic locking

Server

  • Task registration with JSON args
  • Bearer token authentication (require_token)
  • Remote code gating (allow_remote_code requires non-empty token)
  • Configurable request size limits (default: 500MB)
  • Generic 500 error responses, no traceback leakage

Hashing

  • Deterministic cache keys for defaults, module names, bytecode, and custom task names

AsyncExecutor Protocol

  • Pluggable async executors via AsyncExecutor protocol
  • Enables distributed executor implementations (Celery, Kafka, RQ)

Thread Pool Fix

  • BlockingAsyncRunner sets 64-worker default pool instead of min(32, cpu_count+4) to prevent lock contention deadlock on low-core machines

Migration

Redis blob data keys renamed from cashet:blob:{hash} to cashet:blob:data:{hash}. Clear old caches before upgrading if using Redis.

v0.3.0: async client, Redis backend, HTTP server

26 Apr 16:21
698ed0a

Choose a tag to compare

What's new

  • Async clientAsyncClient with submit(), submit_many(), serve() mirroring the sync API, plus AsyncResultRef with concurrent-safe async load()
  • Redis backendRedisStore and AsyncRedisStore with cross-process per-fingerprint locking and O(1) blob ref-counting for efficient GC
  • HTTP server — Starlette + uvicorn with sync and async apps (client.serve()), REST endpoints for submit, result, commit, log, stats, and gc
  • Async SQLite storeAsyncSQLiteStore with inline blob auto_vacuum and VACUUM on close/evict
  • Async executorAsyncLocalExecutor with asyncio-native heartbeat and locking, asyncio.to_thread() for CPU-bound work
  • Extensible extrascashet[redis] and cashet[server] pip extras for optional backends
  • Batch refactorsubmit_many extracted to _batch.py, shared by both sync and async clients

Full diff: v0.2.0...v0.3.0

v0.2.0 — force rerun, task timeouts, parallel batch, inline storage, size-based GC

25 Apr 18:36

Choose a tag to compare

What's new

  • force=True — bypass cache and always re-execute, on both submit() and @client.task
  • Task timeouts — per-task timeout with optional retry (_timeout=30, @client.task(timeout=30))
  • Parallel batch executionsubmit_many(..., max_workers=N) for DAG-aware fan-out
  • Inline blob storage — small objects (<1KB) stored in SQLite for reduced filesystem overhead
  • Size-based GCgc --max-size 1GB evicts oldest entries until under the limit
  • TaskError — now exported from the package

Full diff: 04866df...v0.2.0

Release 0.1.3: cross-process claim dedup, heartbeat leases, and correctness fixes

19 Apr 21:50

Choose a tag to compare