Skip to content

Expiry

@modularityjs/expiry is a zero-dependency primitive that drives the periodic eviction pass of an in-memory TTL store. Like retry and circuit-breaker, it has no module, no DI, and no wiring — import it anywhere.

typescript
import { startExpirySweep } from '@modularityjs/expiry';

const sweep = startExpirySweep(
  () => this.service.sweepExpired(),
  this.config.evictionIntervalMs,
  { label: 'cache-memory' },
);

// later, in onShutdown
sweep.stop();

Why it exists

Every in-memory driver of a TTL-bearing contract needs the same three things, and each one is easy to get subtly wrong on its own:

  1. An unref'd timer, or the sweep keeps the Node event loop alive and the process never exits.
  2. A clearInterval on shutdown, or a restarted app leaks a timer per boot.
  3. Isolation around the sweep, or one throwing eviction pass becomes an uncaughtException and takes the process down — for a background side channel.

That combination was reimplemented six times before this primitive existed. The rule in Lean on Primitives applies to the framework's own packages too: when the same shape appears a third time, extract it.

Behaviour

InputResult
intervalMs: undefinedSweeping disabled; returns an inert handle whose stop() is a no-op — the documented way to opt out
intervalMs: 0, negative, non-integer, NaNThrows a StateException naming the store. A silently-disabled sweep is a memory leak nobody notices
intervalMs > 2³¹−1Throws. setInterval would coerce it to 1 ms and sweep the whole store continuously
sweep() throwsWarns via process.emitWarning (type: 'ModularityJsExpirySweepFailed') and keeps the schedule alive

The returned ExpirySweep handle exposes stop() (idempotent) and a running boolean.

Who uses it

cache-memory, lock-memory, session-memory, rate-limit-memory, auth-local-password-reset-memory, and auth-local-email-verification-memory — each in its module's onInit, stopped in onShutdown. If you write a memory driver with a TTL, use this rather than a seventh copy of the same setInterval.