Files
2026-05-27 23:29:53 +01:00

3.0 KiB

blue-green-slot — hot-reload primitive for the in-memory router

(no submodules)

Purpose

InMemoryBlueGreenSlot is the BlueGreenSlot implementation paired with InMemoryRouter. It is a thin extension of @suaveplan/api-router's reference InMemoryBlueGreenSlot, kept locally so consumers of @suaveplan/api-router-in-memory import their router adapter AND their slot from a single package — symmetric with @suaveplan/api-router-hono's HonoBlueGreenSlot.

The reference implementation in api-router already satisfies every invariant the conformance suite asserts (set/flip/drain/dispose/abort), so this class adds no behaviour; it exists solely to keep the public surface uniform.

Features

  • Inherits the reference impl's three-position state machine (live / shadow / draining).
  • flip() returns a DrainingHandle whose settled promise resolves once all in-flight requests against the previous live slot complete.
  • dispose(slotId, { timeoutMs }) races a timer against drain settle; on timeout, aborts the slot's AbortController and throws ROUTER.SLOT_DISPOSE_TIMEOUT.
  • acquire(slotId) / release(slotId) are wired by the router so the pending counter reflects in-flight dispatch.

Usage: Basic

import { InMemoryBlueGreenSlot } from "@suaveplan/api-router-in-memory/blue-green-slot";

const slot = new InMemoryBlueGreenSlot("billing", () => "v1");
slot.setShadow(() => "v2");
const draining = slot.flip();
// slot.live now serves v2; draining points at the previous v1 slot.
await draining.settled;

Usage: Advanced

Drive a hot-reload from a manifest-driven loader, with abort-on-timeout safety:

import {
    createInMemoryBlueGreenSlot,
} from "@suaveplan/api-router-in-memory/blue-green-slot";

const slot = createInMemoryBlueGreenSlot("billing", () => "v1");
slot.setShadow(() => "v2");
const drain = slot.flip();

try {
    await slot.dispose(drain.slotId, { timeoutMs: 50 });
} catch (err) {
    // dispose timed out — the AbortController on the previous slot has
    // already fired; in-flight handlers should observe their AbortSignal
    // and unwind. Bubble the error up to the reload driver.
    throw err;
}

API Reference

  • class InMemoryBlueGreenSlot extends @suaveplan/api-router.InMemoryBlueGreenSlot
    • constructor(plugin: string, initialHandler: SlotHandler)
    • Inherits live, shadow, setShadow, flip, dispose, acquire, release.
  • createInMemoryBlueGreenSlot(plugin, initialHandler): BlueGreenSlot — convenience factory typed as the abstract interface.

Implementation Notes

The subclass exists to keep the package's exported surface aligned with api-router-hono (HonoBlueGreenSlot is its own concrete class because the live pointer is one mutable field that swaps atomically — see that package's notes). For the in-memory adapter there is no driver-specific work, so this is intentionally a no-op extension. The conformance suite in api-router/testing accepts either the parent class or this subclass.