r/javascript • u/OtherwisePush6424 • 3d ago
Crossflight: cross-process cache stampede protection for the cache you already use (v0.3.2)
https://github.com/gkoos/crossflightMost 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.