import { Keys, Takeover, WorkerRecord } from "./keys.js"; import { createPinboard } from "./server.js"; import { Script } from "./scripts/twins.js"; //#region src/placement.d.ts type RedisKV = createPinboard.RedisKV; type Resolution = { kind: "forward"; worker: WorkerRecord; /** Placement epoch (decimal string): rides every forward as the * Pinboard-Epoch header and quotes releases. */ epoch: string; listed: boolean; /** True when this call created the placement row (nothing activated on * the worker yet). */ fresh: boolean; carriedExpiry?: number; } | { kind: "unknown-ns"; } | { kind: "no-backends"; } | { kind: "quarantine"; retryAfterMs: number; } | { kind: "takeover-pending"; owner: WorkerRecord; /** True when this call issued the wind-down fence. */ initiated: boolean; fenceExpiry: number; } | { kind: "takeover-denied"; }; /** The request's placement world: hostname (compute) and env (data); * SINGLE_WORLD ("*") for both in single-hostname mode. */ type World = { hostname: string; env: string; takeover: Takeover; }; declare const runScript: (redis: RedisKV, script: Script.Def, keys: string[], argv: string[]) => Promise; /** Sets (or clears, atMs = null) the wind-down expiry on each placed id in * one bucket's placements hash; returns the (id, owning sessionId) pairs. */ declare const windDownPlacements: (redis: RedisKV, placementsKey: string, ids: string[], atMs: number | null) => Promise<{ id: string; sessionId: string; }[]>; /** Single-id wind_down; returns the owning sessionId, or null when unplaced. */ declare const windDownPlacement: (redis: RedisKV, keys: Keys, env: string, ns: string, id: string, atMs: number | null) => Promise; /** Compare-and-delete on (sessionId, epoch); an entry without an epoch quotes * an epoch-less row. Returns the number of rows freed. */ declare const releasePlacements: (redis: RedisKV, keys: Keys, env: string, ns: string, sessionId: string, entries: { id: string; epoch?: string | undefined; }[]) => Promise; /** Atomic read-modify-write of one ns_workers field, pruning dead sessions. */ declare const updateNsWorkers: (redis: RedisKV, keys: Keys, bucket: number, field: string, sessionId: string, op: "add" | "remove", now: number) => Promise; declare namespace createPlacer { type Options = { leaseTtlMs: number; /** Bounded-load factor c: a preference is honored only while the * preferred worker's headroom stays >= mean(headrooms) / c. Default 1.25. */ balanceFactor?: number | undefined; now?: (() => number) | undefined; random?: (() => number) | undefined; /** Outlier-ejected sessionIds, withheld from new placements while any * other candidate remains. */ ejected?: (() => readonly string[]) | undefined; }; type Preference = { /** Exact co-location target; wins over affinityKey. */ preferredSessionId?: string | undefined; /** Rendezvous-hashed over live candidates to derive a preferred worker. */ affinityKey?: string | undefined; }; type Instance = { resolve(world: World, ns: string, id: string, preference?: Preference, /** Never place on this session (in-band activation NACK re-place). */ exclude?: string): Promise; }; } /** * Placement path: one atomic read-or-allocate script per resolve. The script * stamps the bucket's boot_time (SET NX, no TTL) and refuses new placements * while now < boot_time + lease window, so a wiped bucket self-quarantines * for one lease window while surviving buckets keep serving. */ declare const createPlacer: (redis: RedisKV, keys: Keys, options: createPlacer.Options) => createPlacer.Instance; //#endregion export { Resolution, World, createPlacer, releasePlacements, runScript, updateNsWorkers, windDownPlacement, windDownPlacements }; //# sourceMappingURL=placement.d.ts.map