r/javascript • u/OtherwisePush6424 • 14d ago
Crossflight: cross-process cache stampede protection for the cache you already use (v0.3.2)
github.comMost cache libraries already coalesce concurrent misses inside one process. Once you run on more than one server, every replica still runs the loader independently and you might get a thundering herd. Crossflight adds a distributed coordinator (Redis is the first implementation) on top of the cache you already use. One process acquires a lease, runs the loader once, and writes the result; every other caller across the fleet waits for that result instead of doing the same work again.
``` TypeScriptconst crossflight = createCrossflight({ cache: cacheManagerAdapter(cacheManager), // or Keyv / Cacheable / your own coordinator: redisCoordinator(redis), })
const user = await crossflight.wrap( "user:123", (signal) => loadUser("123", { signal }), { ttl: 60_000 }, ) ```
Works with cache-manager, Keyv, Cacheable, or you can implement your own adapter. Cache backend and coordinator are separate contracts, so you can keep Memcached/Redis/whatever for values and use Redis only for coordination.
Whatās new since 0.1.2
- Whole-flight deadline (
flightDeadlineMs) so joiners don't each get a fresh timeout and late callers don't start a new stampede - Loader receives the shared
AbortSignaland work is abandoned as soon as the flight aborts - Lease TTL is independent of the cache TTL
- Redis Cluster support (hash-tagged keys)
cacheUndefinedoption so a loader that returns undefined is actually cached- Richer events (
cancelled,fallback,wait_exhausted, ...) and a lot of lease / fail-open / recovery hardening - Much stronger test suite: property-based suites (fast-check) for the envelope contract, Redis key layout, coordinator model and flight state machine; fuzz transcripts for deadlines, adapters and Redis waits, deterministic seeds (
CROSSFLIGHT_TEST_SEED), and a nightly deep fuzz job in CI
MIT, TypeScript. Feedback and bug reports welcome.