@mark1russell7/service 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -0
- package/build/{builder-BzjhWk2E.d.ts → builder-DyDB7zM9.d.ts} +9 -2
- package/build/http.d.ts +9 -1
- package/build/http.js +25 -1
- package/build/http.js.map +1 -1
- package/build/index.d.ts +30 -8
- package/build/index.js +117 -5
- package/build/index.js.map +1 -1
- package/build/{lifecycle-DjEpgpRk.d.ts → lifecycle-Chu9Pri2.d.ts} +7 -1
- package/build/limiter-DzTyosou.d.ts +72 -0
- package/build/limiter-wv0uXDk9.js +126 -0
- package/build/limiter-wv0uXDk9.js.map +1 -0
- package/build/limiter.d.ts +3 -0
- package/build/limiter.js +3 -0
- package/build/policy-CgS4y94U.js +187 -0
- package/build/policy-CgS4y94U.js.map +1 -0
- package/build/policy-G4QJ1ZZq.d.ts +176 -0
- package/build/redis.d.ts +2 -2
- package/build/testing.d.ts +2 -2
- package/package.json +9 -4
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["message","isAsyncIterable","isTime","boundOf","r","OWNER"],"sources":["../src/description.ts","../src/latch.ts","../src/poller.ts","../src/health.ts","../src/process.ts","../src/routes.ts","../src/requests.ts","../src/lifecycle.ts","../src/watchdog.ts","../src/builder.ts","../src/law.ts","../src/lint.ts","../src/profiles.ts","../src/units.ts","../src/worker.ts","../src/queue.ts","../src/machines.ts"],"sourcesContent":["import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport type { Operation } from \"./operation.ts\";\nimport type { ExitSignal, ExitTrigger, MessageShape, ProcessTrigger } from \"./process.ts\";\nimport type { RoutePattern } from \"./routes.ts\";\nimport type { Poll, Timing } from \"./timing.ts\";\n\n/**\n * This is the format of a service as data: what `describe()` exports, and nothing starts. The\n * timer algebra and the ordering law read it. Each timer has a unit. Each knob comes from the\n * declaration, because the runtime has no defaults. A bound that nobody gives is \"no bound\", not\n * zero.\n */\nexport const FORMAT = \"mark1russell7.service/1\";\n\n/** A step is a step of a connection that a check examines. A check that skips a step cannot see a failure in it. */\nexport type Step =\n \"dial\" | \"local-state\" | \"round-trip\" | \"checkout\" | \"progress\" | \"topology\" | \"latency\";\n\n/** A gate is the policy that the failures of a check count toward. */\nexport type Gate = \"readiness\" | \"liveness\";\n\n/** A check is an active check: one signal, for one step of a connection. */\nexport interface Check {\n readonly name: string;\n /** This name is the dependency that it examines, or null when it reads the state of the process. */\n readonly dependency: string | null;\n readonly step: Step;\n /** This flag tells if it uses the connection of the application. A check on its own connection cannot see a failure of that connection. */\n readonly ownConnection: boolean;\n /** This gate is the policy that it controls, or null for a check that only reports. It has no default. */\n readonly gates: Gate | null;\n readonly poll: Poll;\n}\n\n/**\n * A dependency is something that the service uses, with its client. Its knobs have the names that\n * the ordering law uses: `request_timeout`, `connect_bound`, `driver_writeoff_time`,\n * `heartbeat_interval`, `client_retry_window`. Thus the law reads them without a translation.\n */\nexport interface Dependency {\n readonly name: string;\n /** This identifier is the component in the corpus (`systems.component.postgresql`), or null when the corpus does not have it. */\n readonly system: string | null;\n readonly knobs: Readonly<Record<string, Extent>>;\n /**\n * These are the operations that the service does with it, by name (`GET /v1/forecast`, `INCR`).\n * Each operation declares if it can go again. A dependency usually has the two kinds, thus a\n * dependency has no idempotency of its own. An operation without a declaration does not go again.\n */\n readonly operations: Readonly<Record<string, Operation>>;\n}\n\n/**\n * A transport is something that takes work in: a server, a consumer or a worker. Each is a\n * component with a state machine. The service is ready only while each transport takes work.\n */\nexport interface Transport {\n readonly name: string;\n readonly kind: \"server\" | \"consumer\" | \"worker\";\n /** These are its knobs, with the names of the law where the law has them: the `server_idle_close` of a server. */\n readonly knobs: Readonly<Record<string, Extent>>;\n}\n\n/**\n * A controller is a group of routes. It is ready only while the dependencies that it needs are\n * ready. Each route declares if its callers can send it again. When the shutdown stops a request,\n * an idempotent route answers 503, which a caller can retry. Other routes answer 500.\n */\nexport interface Controller {\n readonly name: string;\n readonly requires: readonly string[];\n readonly routes: Readonly<Record<string, Operation>>;\n /**\n * These patterns match the routes that `routes` does not name, in their sequence: the first\n * pattern that matches a route gives its operations. Without a declaration, the controller has\n * no patterns.\n */\n readonly patterns?: readonly RoutePattern[] | undefined;\n}\n\n/** A coupling is a declared edge between two policies. The algebra checks its margin. */\nexport interface Coupling {\n readonly from: Gate;\n readonly to: Gate;\n readonly effect: \"fails\";\n}\n\n/** A phase is one step of the shutdown sequence, with a cap. Its owner adds it. */\nexport interface Phase {\n readonly name: string;\n readonly cap: Quantity;\n}\n\n/**\n * A repeat signal policy tells what an exit signal does while the shutdown runs:\n * - `ignore`: the signal has no effect, and the shutdown continues.\n * - `exit`: the process exits with the code 1 at once, as a second Ctrl-C does in a terminal.\n */\nexport type RepeatSignal = \"ignore\" | \"exit\";\n\n/**\n * A cooperative floor is the earliest time of the cooperative abort in the drain:\n * - `half`: half the cap of the drain. The work in flight gets half the drain at the least.\n * - `none`: no floor. A window of the whole cap or more aborts the work at the start of the drain.\n */\nexport type CooperativeFloor = \"half\" | \"none\";\n\n/** These exit codes replace the code 0 of a clean shutdown, by the trigger of the shutdown. */\nexport type ExitCodes = Readonly<Partial<Record<ExitTrigger, number>>>;\n\n/**\n * A message trigger is a message of the IPC channel that starts the shutdown, for the trigger\n * `ipc-message`. With `as`, the message is that exit signal: it has its exit code and the policy of a\n * repeat signal. Without `as`, the message is the trigger `ipc-message`.\n */\nexport interface MessageTrigger {\n /** This shape is the message that starts the shutdown, for example `\"shutdown\"`. */\n readonly match: MessageShape;\n /** This signal is the exit signal that the message replaces, for example `SIGTERM` on Windows. */\n readonly as?: ExitSignal | undefined;\n}\n\n/** A service description is the whole graph of a service, as data. */\nexport interface ServiceDescription {\n readonly format: typeof FORMAT;\n readonly name: string;\n /** This flag tells if a part joined after the start. That part starts tripped, and the export is partial. */\n readonly partial: boolean;\n readonly transports: readonly Transport[];\n readonly dependencies: readonly Dependency[];\n readonly controllers: readonly Controller[];\n readonly checks: readonly Check[];\n readonly policies: {\n readonly readiness: Timing;\n readonly liveness: Timing;\n /** This duration is how long the service can take to start. The startup probe must agree with it. */\n readonly startup: Quantity;\n };\n readonly couplings: readonly Coupling[];\n readonly shutdown: {\n readonly phases: readonly Phase[];\n /** This window is how long before the end of the drain the cooperative abort occurs, or no bound. */\n readonly cooperativeWindow: Extent;\n /** This floor is the earliest time of the cooperative abort. Without a declaration, the floor is `half`. */\n readonly cooperativeFloor?: CooperativeFloor | undefined;\n /** This policy tells what a signal does while the shutdown runs. Each declaration gives it, because the runtime has no defaults. */\n readonly onRepeatSignal: RepeatSignal;\n /** These triggers start the shutdown, in addition to the exit signals. Each one is opt-in. */\n readonly triggers?: readonly ProcessTrigger[] | undefined;\n /** These messages of the IPC channel start the shutdown. The trigger `ipc-message` needs one at the least. */\n readonly messages?: readonly MessageTrigger[] | undefined;\n /** These codes replace the exit code 0 by the trigger. Without a code, a clean shutdown exits 0. */\n readonly exitCodes?: ExitCodes | undefined;\n };\n}\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { Timing } from \"./timing.ts\";\n\n/**\n * An outcome is the result of one poll of a check. Only `\"ok\"` passes. An `\"indeterminate\"`\n * outcome measured nothing: it does not pass, and it does not fail.\n */\nexport type Outcome = \"ok\" | \"error\" | \"indeterminate\";\n\n/** A result is one poll of a check, as the runtime records it. */\nexport interface Result {\n readonly outcome: Outcome;\n /** This time is when the result came, on the monotonic clock, in milliseconds. */\n readonly at: number;\n /** This time is how long the poll took, in milliseconds. */\n readonly took: number;\n /** This text tells why the poll did not pass, or it is null. */\n readonly cause: string | null;\n /** This flag tells if the poll failed at its timeout. */\n readonly timedOut: boolean;\n /** This flag tells if the check threw. A throw is an error with a flag. */\n readonly thrown: boolean;\n /** This flag tells if the force-fail list made the poll fail. */\n readonly forced: boolean;\n}\n\n/**\n * A latch turns the results of one check into a verdict, by the timing of its policy. A debounce\n * counts polls in sequence. A window measures time on the monotonic clock from the first failure\n * of a sequence. A tripped latch fails its policy.\n */\nexport interface Latch {\n readonly tripped: boolean;\n /** This time is when the latch last tripped or released. */\n readonly since: number;\n /** This count is the sequence of the latest results: above zero for passes, below zero for failures. */\n readonly streak: number;\n record(result: Result): void;\n /** This method stops the timers of a window. */\n stop(): void;\n}\n\n/**\n * A trace receives each transition of a machine of the runtime: the state before, the state after,\n * and the event. The machine documents of the lifecycle name the same states and events, thus a\n * test can replay a trace against its document.\n */\nexport type Trace = (from: string, to: string, on: string) => void;\n\nconst ms = (amount: { readonly value: number; readonly unit: string }): number =>\n valueIn(amount, \"ms\");\n\n/**\n * This function makes a latch. `tripped` is its state at the start: a readiness latch starts\n * tripped, and a liveness latch starts released. The latch starts `changed` each time it trips or\n * releases, and it gives each transition to `trace`. A debounce has the states `released` and\n * `tripped`. A window also has the states `failing` and `recovering`, while one of its timers runs.\n */\nexport const latch = (\n timing: Timing,\n clock: Clock,\n tripped: boolean,\n changed: () => void,\n trace?: Trace,\n): Latch => {\n let state = tripped;\n let since = clock.now();\n let streak = 0;\n let fails = 0;\n let passes = 0;\n // the timers of a window: the time that a sequence of failures or passes started, and its timer\n let failingSince: number | null = null;\n let passingSince: number | null = null;\n let failTimer: Cancel | null = null;\n let passTimer: Cancel | null = null;\n\n /** This function gives the name of the state, as the machine documents name it. */\n const named = (): string =>\n state\n ? passingSince === null\n ? \"tripped\"\n : \"recovering\"\n : failingSince === null\n ? \"released\"\n : \"failing\";\n /** This function does one step of the machine, and gives its transition to the trace. */\n const step = (on: string, change: () => void): void => {\n const from = named();\n change();\n trace?.(from, named(), on);\n };\n\n const set = (next: boolean): void => {\n if (next === state) return;\n state = next;\n since = clock.now();\n changed();\n };\n const stopFail = (): void => {\n failTimer?.();\n failTimer = null;\n failingSince = null;\n };\n const stopPass = (): void => {\n passTimer?.();\n passTimer = null;\n passingSince = null;\n };\n\n const debounce = (result: Result): void => {\n if (timing.type !== \"debounce\") return;\n if (result.outcome === \"ok\") {\n passes += 1;\n fails = 0;\n if (state && passes >= timing.recoverAfter) set(false);\n } else {\n fails += 1;\n passes = 0;\n if (!state && fails >= timing.failAfter) set(true);\n }\n };\n\n const windowed = (result: Result): void => {\n if (timing.type !== \"window\") return;\n if (result.outcome === \"ok\") {\n stopFail();\n if (!state) return;\n if (timing.recoverAfter === undefined) {\n set(false);\n return;\n }\n if (passingSince !== null) return;\n const wait = ms(timing.recoverAfter);\n if (wait <= 0) {\n stopPass();\n set(false);\n return;\n }\n passingSince = result.at;\n passTimer = clock.after(wait, () =>\n step(\"window.recovered\", () => {\n passTimer = null;\n passingSince = null;\n set(false);\n }),\n );\n return;\n }\n stopPass();\n if (state || failingSince !== null) return;\n const wait = ms(timing.failAfter);\n if (wait <= 0) {\n stopFail();\n set(true);\n return;\n }\n failingSince = result.at;\n failTimer = clock.after(wait, () =>\n step(\"window.failed\", () => {\n failTimer = null;\n failingSince = null;\n set(true);\n }),\n );\n };\n\n return {\n get tripped() {\n return state;\n },\n get since() {\n return since;\n },\n get streak() {\n return streak;\n },\n record(result) {\n // an indeterminate poll measured nothing: it moves no sequence and no streak\n if (result.outcome === \"indeterminate\") return;\n const pass = result.outcome === \"ok\";\n step(pass ? \"poll.ok\" : \"poll.fail\", () => {\n streak = pass ? Math.max(0, streak) + 1 : Math.min(0, streak) - 1;\n debounce(result);\n windowed(result);\n });\n },\n stop() {\n stopFail();\n stopPass();\n },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { Outcome, Result, Trace } from \"./latch.ts\";\nimport type { Poll } from \"./timing.ts\";\n\n/**\n * A check function measures one step of a connection. It ends with nothing or `\"ok\"` for a pass,\n * or with `\"error\"` or `\"indeterminate\"`. A throw is an error with a flag. The runtime aborts the\n * signal at the timeout of the poll.\n */\nexport type CheckFn = (signal: AbortSignal) => Outcome | void | Promise<Outcome | void>;\n\n/** A poller starts one check on its own loop, and gives each result to `record`. */\nexport interface Poller {\n /** This result is the latest one, or null before the first poll. */\n readonly last: Result | null;\n /** This method polls one time at once, outside the loop, and gives the result. */\n pollNow(): Promise<Result>;\n /** This method starts the loop. The first poll of the loop comes after `delay` milliseconds. */\n start(delay: number): void;\n /** This method gives the next delay of the loop: the interval, with the jitter. */\n jittered(): number;\n stop(): void;\n}\n\nexport interface PollerOptions {\n readonly name: string;\n readonly poll: Poll;\n readonly run: CheckFn;\n readonly clock: Clock;\n readonly random: () => number;\n /** This function tells if the force-fail list names the check at this time. */\n readonly forced: () => boolean;\n readonly record: (result: Result) => void;\n /**\n * This function receives each transition of the poller. Its states are `idle`, `waiting`,\n * `calling`, `hung` (a call that outlived its timeout) and `stopped`.\n */\n readonly trace?: Trace | undefined;\n}\n\nconst message = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * This function makes a poller. The loop is on a fixed delay from the start of each poll. Thus the\n * next poll starts one interval after the current poll starts, with the jitter (±20 % is 0.2).\n * The timing algebra of the declaration uses this model.\n *\n * Each poll makes a new measurement. While a use of the check is pending, the poller does not\n * start the check again. Such a poll fails at once with the same cause, and the sequence of\n * failures continues.\n */\nexport const poller = (options: PollerOptions): Poller => {\n const { clock, poll, run } = options;\n const interval = valueIn(poll.interval, \"ms\");\n const timeout = valueIn(poll.timeout, \"ms\");\n let last: Result | null = null;\n let next: Cancel | null = null;\n let stopped = false;\n let looping = false;\n // the call that has not ended, and when it started; `late` once the call outlived its timeout\n let pending: { readonly since: number; late: boolean } | null = null;\n // the polls in flight: stop() ends each one, and its timer\n const active = new Set<() => void>();\n\n /** This function gives the name of the state, as the machine document of the poller names it. */\n const named = (): string =>\n stopped\n ? \"stopped\"\n : pending !== null\n ? pending.late\n ? \"hung\"\n : \"calling\"\n : looping\n ? \"waiting\"\n : \"idle\";\n const step = (on: string, change: () => void): void => {\n const from = named();\n change();\n options.trace?.(from, named(), on);\n };\n\n const result = (\n outcome: Outcome,\n started: number,\n fields: Partial<Pick<Result, \"cause\" | \"timedOut\" | \"thrown\" | \"forced\">> = {},\n ): Result => ({\n outcome,\n at: clock.now(),\n took: clock.now() - started,\n cause: fields.cause ?? null,\n timedOut: fields.timedOut ?? false,\n thrown: fields.thrown ?? false,\n forced: fields.forced ?? false,\n });\n\n const once = (): Promise<Result> => {\n const started = clock.now();\n if (options.forced())\n return Promise.resolve(result(\"error\", started, { cause: \"the force-fail list names it\", forced: true }));\n if (pending !== null) {\n const cause = `its call of ${Math.round(started - pending.since)} ms ago is still pending`;\n return Promise.resolve(result(\"error\", started, { cause }));\n }\n const controller = new AbortController();\n return new Promise<Result>((resolve) => {\n let done = false;\n const finish = (value: Result): void => {\n if (done) return;\n done = true;\n active.delete(abandon);\n cancel();\n resolve(value);\n };\n const abandon = (): void => {\n controller.abort();\n finish(result(\"error\", started, { cause: \"the runtime stopped\" }));\n };\n active.add(abandon);\n const call = { since: started, late: false };\n pending = call;\n const cancel = clock.after(timeout, () => {\n controller.abort();\n // the poll fails at its timeout. The call stays pending until it settles\n step(\"timeout\", () => {\n if (pending === call) call.late = true;\n });\n finish(result(\"error\", started, { cause: `no answer in ${timeout} ms`, timedOut: true }));\n });\n const settled = (): void => {\n if (pending !== call) return;\n step(call.late ? \"late-answer\" : \"answer\", () => {\n pending = null;\n });\n };\n let answer: Promise<Outcome | void>;\n try {\n answer = Promise.resolve(run(controller.signal));\n } catch (error) {\n answer = Promise.reject(error);\n }\n answer.then(\n (value) => {\n settled();\n const outcome = value ?? \"ok\";\n finish(result(outcome, started, outcome === \"ok\" ? {} : { cause: `the check gave ${outcome}` }));\n },\n (error: unknown) => {\n settled();\n finish(result(\"error\", started, { cause: message(error), thrown: true }));\n },\n );\n });\n };\n\n const handle = (value: Result): Result => {\n last = value;\n if (!stopped) options.record(value);\n return value;\n };\n\n const jittered = (): number => interval * (1 + poll.jitter * (2 * options.random() - 1));\n\n const tick = (): void => {\n next = null;\n if (stopped) return;\n let polled: Promise<Result> | undefined;\n step(\"tick\", () => {\n next = clock.after(jittered(), tick);\n polled = once();\n });\n void polled!.then(handle);\n };\n\n return {\n get last() {\n return last;\n },\n pollNow: () => {\n let polled: Promise<Result> | undefined;\n step(\"sweep\", () => {\n polled = once();\n });\n return polled!.then(handle);\n },\n start(delay) {\n if (stopped || next !== null) return;\n step(\"start\", () => {\n looping = true;\n next = clock.after(Math.max(0, delay), tick);\n });\n },\n jittered,\n stop() {\n if (stopped) return;\n step(\"stop\", () => {\n stopped = true;\n next?.();\n next = null;\n });\n for (const abandon of [...active]) abandon();\n },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { Check, Gate, ServiceDescription } from \"./description.ts\";\nimport type { MachineName, Recorder } from \"./events.ts\";\nimport type { Latch, Result, Trace } from \"./latch.ts\";\nimport { latch } from \"./latch.ts\";\nimport type { CheckFn, Poller } from \"./poller.ts\";\nimport { poller } from \"./poller.ts\";\n\n/** These options start the runtime. Without them, it uses the real clock and `Math.random`. */\nexport interface StartOptions {\n readonly clock?: Clock | undefined;\n /** This function gives a number in [0, 1) for the jitter of each poll. */\n readonly random?: (() => number) | undefined;\n /** This list names the checks or dependencies whose polls fail at once (a seam for tests). */\n readonly forceFail?: readonly string[] | undefined;\n /** This function receives each transition of each machine of the runtime. */\n readonly record?: Recorder | undefined;\n /**\n * This function can replace the function of a check, for example to add a delay to each call\n * (a seam for tests: a degraded dependency). It gives the function to use.\n */\n readonly wrapCheck?: ((check: Check, run: CheckFn) => CheckFn) | undefined;\n}\n\n/** A check verdict is the cached state of one check, for the probes and the report. */\nexport interface CheckVerdict {\n readonly gates: Gate | null;\n readonly dependency: string | null;\n /** This flag tells if the latch of the check is tripped, or it is null for a check that only reports. */\n readonly tripped: boolean | null;\n readonly streak: number;\n /** This time is when the latch last changed, in milliseconds on the monotonic clock. */\n readonly since: number | null;\n readonly last: Result | null;\n}\n\n/** A verdict is the state of the service, from its cache. Nothing in it starts a check. */\nexport interface HealthVerdict {\n /** This flag becomes true one time, after the warm-up sweep. */\n readonly started: boolean;\n readonly draining: boolean;\n /** This flag tells if the service can take new work: started, not draining, and each readiness latch released. */\n readonly ready: boolean;\n /** This flag tells if each liveness latch is released. */\n readonly alive: boolean;\n /** These flags tell if each controller can take new work, from the dependencies that it needs. */\n readonly controllers: Readonly<Record<string, boolean>>;\n readonly dependencies: Readonly<Record<string, boolean>>;\n readonly checks: Readonly<Record<string, CheckVerdict>>;\n readonly startup: { readonly budget: number; readonly elapsed: number; readonly overBudget: boolean };\n}\n\n/** A probe kind is the question that a probe asks: the startup, the readiness, the liveness, or the whole report. */\nexport type ProbeKind = \"startup\" | \"readiness\" | \"liveness\" | \"report\";\n\n/** A probe answer is a status and a body, for any HTTP framework or none. */\nexport interface ProbeAnswer {\n readonly status: 200 | 503;\n readonly contentType: \"application/health+json\";\n readonly body: {\n readonly status: \"pass\" | \"fail\";\n readonly service: string;\n readonly probe: ProbeKind;\n readonly controller?: string | undefined;\n readonly verdict?: HealthVerdict | undefined;\n };\n}\n\n/** The health runtime of a started service. It reads its timing and its checks from the declaration. */\nexport interface Health {\n verdict(): HealthVerdict;\n /**\n * This method answers a probe from the cache, in constant time, and it starts no check. A\n * readiness probe with a controller asks about that controller. The report always answers 200.\n */\n probe(kind: ProbeKind, controller?: string): ProbeAnswer;\n /** This method gives each change of the verdict to `listener`, and gives the function that stops it. */\n subscribe(listener: (verdict: HealthVerdict) => void): () => void;\n /** This method adds a name to the force-fail list, or removes it. */\n forceFail(name: string, on: boolean): void;\n /** This method fails readiness for good. The drain of the lifecycle starts with it. */\n drain(): void;\n /** This method stops each poller and each timer of the runtime. */\n stop(): void;\n}\n\n/** The runtime parts that the builder and the lifecycle use. */\nexport interface Runtime extends Health {\n /**\n * This method opens the startup gate: one bounded warm-up sweep of each check, then the loops of\n * the pollers. It is idempotent, and it does nothing after `failStartup()` or `stop()`.\n */\n warmUp(): Promise<void>;\n /** This method moves the gate from `closed` to `starting`: the lifecycle starts its components. */\n beginStartup(): void;\n /** This method moves the gate to `failed` for good: a component did not start. */\n failStartup(cause: string): void;\n addCheck(check: Check, run: CheckFn): void;\n addDependency(name: string): void;\n}\n\ninterface Entry {\n readonly check: Check;\n readonly poller: Poller;\n readonly latch: Latch | null;\n}\n\n/**\n * This function makes the runtime of a declaration. The service has no defaults of its own: each\n * timing, poll and coupling comes from the description.\n */\nexport const healthRuntime = (\n description: ServiceDescription,\n runs: ReadonlyMap<string, CheckFn>,\n options: StartOptions = {},\n): Runtime => {\n const clock = options.clock ?? realClock;\n const random = options.random ?? Math.random;\n const forced = new Set(options.forceFail ?? []);\n const startedAt = clock.now();\n const budget = valueIn(description.policies.startup, \"ms\");\n const entries = new Map<string, Entry>();\n const dependencies = new Set(description.dependencies.map((dependency) => dependency.name));\n // a dependency that joined after the start is tripped until a check on it passes one time\n const lateDependencies = new Set<string>();\n const listeners = new Set<(verdict: HealthVerdict) => void>();\n let started = false;\n let draining = false;\n let stopped = false;\n // the startup gate: closed, starting (components start), sweeping (the warm-up), open or failed\n let gate = \"closed\";\n\n const tracer =\n (machine: MachineName, instance: string): Trace =>\n (from, to, on) =>\n options.record?.({ at: clock.now(), machine, instance, from, to, on });\n const gateTrace = tracer(\"gate\", description.name);\n const moveGate = (to: string, on: string, detail?: string): void => {\n const from = gate;\n gate = to;\n options.record?.({\n at: clock.now(),\n machine: \"gate\",\n instance: description.name,\n from,\n to,\n on,\n ...(detail === undefined ? {} : { detail }),\n });\n };\n // the startup budget: a gate that is not open at its end says so. The platform's startup probe\n // acts on it, and the runtime does not stop itself\n let budgetTimer: Cancel | null = clock.after(budget, () => {\n budgetTimer = null;\n if (gate !== \"open\" && gate !== \"failed\") gateTrace(gate, gate, \"startup.over-budget\");\n });\n\n const changed = (): void => {\n if (listeners.size === 0) return;\n const now = verdict();\n for (const listener of listeners) listener(now);\n };\n\n const add = (check: Check, given: CheckFn, late: boolean): void => {\n const run = options.wrapCheck?.(check, given) ?? given;\n const timing = check.gates === null ? null : description.policies[check.gates];\n // readiness is earned: its latch starts tripped. Liveness passes from the start (and a late\n // liveness check starts released too, or one late registration could restart the process)\n const made =\n timing === null\n ? null\n : latch(\n timing,\n clock,\n check.gates === \"readiness\",\n changed,\n tracer(timing.type === \"window\" ? \"window\" : \"latch\", check.name),\n );\n const entry: Entry = {\n check,\n latch: made,\n poller: poller({\n name: check.name,\n poll: check.poll,\n run,\n clock,\n random,\n forced: () =>\n forced.has(check.name) || (check.dependency !== null && forced.has(check.dependency)),\n record: (result) => {\n made?.record(result);\n // a late dependency is released by the first pass of a check on it\n if (result.outcome === \"ok\" && check.dependency !== null)\n if (lateDependencies.delete(check.dependency)) changed();\n },\n trace: tracer(\"poller\", check.name),\n }),\n };\n entries.set(check.name, entry);\n if (late && !stopped) {\n // a late registration pulls readiness until its first pass: it polls at once, then on its loop\n void entry.poller.pollNow();\n entry.poller.start(entry.poller.jittered());\n }\n };\n\n for (const check of description.checks) {\n const run = runs.get(check.name);\n if (run === undefined) throw new Error(`check ${check.name} has no function: the runtime has no defaults`);\n add(check, run, false);\n }\n\n const latchesOf = (gateOf: Gate, keep: (check: Check) => boolean = () => true): Latch[] =>\n [...entries.values()].flatMap((entry) =>\n entry.check.gates === gateOf && entry.latch !== null && keep(entry.check) ? [entry.latch] : [],\n );\n const released = (latches: readonly Latch[]): boolean => latches.every((each) => !each.tripped);\n /** This function tells if a policy fails through a declared coupling from another policy. */\n const coupledOff = (to: Gate, base: Record<Gate, boolean>): boolean =>\n description.couplings.some((coupling) => coupling.to === to && !base[coupling.from]);\n\n const verdict = (): HealthVerdict => {\n const base: Record<Gate, boolean> = {\n readiness: released(latchesOf(\"readiness\")) && lateDependencies.size === 0,\n liveness: released(latchesOf(\"liveness\")),\n };\n const alive = base.liveness && !coupledOff(\"liveness\", base);\n const open = started && !draining && !coupledOff(\"readiness\", base);\n const ready = open && base.readiness;\n const dependencyReady = (name: string): boolean =>\n !lateDependencies.has(name) &&\n released(latchesOf(\"readiness\", (check) => check.dependency === name));\n const own = released(latchesOf(\"readiness\", (check) => check.dependency === null));\n const dependenciesOut: Record<string, boolean> = {};\n for (const name of dependencies) dependenciesOut[name] = dependencyReady(name);\n const controllers: Record<string, boolean> = {};\n for (const controller of description.controllers)\n controllers[controller.name] = open && own && controller.requires.every(dependencyReady);\n const checks: Record<string, CheckVerdict> = {};\n for (const [name, entry] of entries) {\n checks[name] = {\n gates: entry.check.gates,\n dependency: entry.check.dependency,\n tripped: entry.latch?.tripped ?? null,\n streak: entry.latch?.streak ?? 0,\n since: entry.latch?.since ?? null,\n last: entry.poller.last,\n };\n }\n const elapsed = clock.now() - startedAt;\n return {\n started,\n draining,\n ready,\n alive,\n controllers,\n dependencies: dependenciesOut,\n checks,\n startup: { budget, elapsed, overBudget: !started && elapsed > budget },\n };\n };\n\n const answer = (kind: ProbeKind, pass: boolean, controller?: string): ProbeAnswer => ({\n status: pass || kind === \"report\" ? 200 : 503,\n contentType: \"application/health+json\",\n body: {\n status: pass ? \"pass\" : \"fail\",\n service: description.name,\n probe: kind,\n ...(controller === undefined ? {} : { controller }),\n ...(kind === \"report\" ? { verdict: verdict() } : {}),\n },\n });\n\n return {\n verdict,\n probe(kind, controller) {\n const now = verdict();\n if (kind === \"startup\") return answer(kind, now.started);\n if (kind === \"liveness\") return answer(kind, now.alive);\n if (kind === \"report\") return answer(kind, now.ready && now.alive);\n if (controller === undefined) return answer(kind, now.ready);\n const known = now.controllers[controller];\n if (known === undefined) throw new Error(`${description.name} has no controller ${controller}`);\n return answer(kind, known, controller);\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n forceFail(name, on) {\n if (on) forced.add(name);\n else forced.delete(name);\n },\n drain() {\n if (draining) return;\n draining = true;\n changed();\n },\n stop() {\n stopped = true;\n budgetTimer?.();\n budgetTimer = null;\n for (const entry of entries.values()) {\n entry.poller.stop();\n entry.latch?.stop();\n }\n },\n beginStartup() {\n if (gate === \"closed\") moveGate(\"starting\", \"startup.begin\");\n },\n failStartup(cause) {\n if (gate === \"open\" || gate === \"failed\") return;\n moveGate(\"failed\", \"startup.fail\", cause);\n budgetTimer?.();\n budgetTimer = null;\n },\n async warmUp() {\n if (started || stopped || gate === \"failed\" || gate === \"sweeping\") return;\n moveGate(\"sweeping\", \"mark-ready\");\n // one bounded sweep of each check: each poll ends at its timeout at the latest\n const sweep = clock.now();\n await Promise.all([...entries.values()].map((entry) => entry.poller.pollNow()));\n if (stopped || gate !== \"sweeping\") return;\n for (const entry of entries.values())\n entry.poller.start(entry.poller.jittered() - (clock.now() - sweep));\n started = true;\n budgetTimer?.();\n budgetTimer = null;\n moveGate(\"open\", \"sweep.done\");\n changed();\n },\n addCheck(check, run) {\n if (entries.has(check.name)) throw new Error(`${description.name} already has a check named ${check.name}`);\n add(check, run, true);\n changed();\n },\n addDependency(name) {\n if (dependencies.has(name)) return;\n dependencies.add(name);\n lateDependencies.add(name);\n changed();\n },\n };\n};\n","/** An exit signal is a signal that asks the process to stop: each one starts the shutdown. */\nexport type ExitSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGQUIT\";\n\n/** These are the signals that the runtime handles. */\nexport const EXIT_SIGNALS: readonly ExitSignal[] = [\"SIGINT\", \"SIGTERM\", \"SIGQUIT\"];\n\n/**\n * A process trigger is an event of the process, other than a signal, that starts the shutdown. A\n * declaration opts in to each one (`svc.trigger`):\n * - `stdin-close`: the standard input ends or closes, as when the parent of a stdio child goes away.\n * The process must read its input, as a stdio transport does, or Node does not see the end.\n * - `ipc-close`: the IPC channel to the parent process closes.\n * - `ipc-message`: a message on the IPC channel matches a declared shape. Windows cannot give a\n * child a SIGTERM that the child can catch, thus a parent sends a message.\n */\nexport type ProcessTrigger = \"stdin-close\" | \"ipc-close\" | \"ipc-message\";\n\n/** These are the process triggers that a declaration can opt in to. */\nexport const PROCESS_TRIGGERS: readonly ProcessTrigger[] = [\"stdin-close\", \"ipc-close\", \"ipc-message\"];\n\n/** An exit trigger is an event that starts the shutdown: an exit signal, or a declared process trigger. */\nexport type ExitTrigger = ExitSignal | ProcessTrigger;\n\n/** This function tells if a number is an exit code of a process: a whole number from 0 to 255. */\nexport const isExitCode = (code: number): boolean => Number.isInteger(code) && code >= 0 && code <= 255;\n\n/** This function tells if a trigger is an exit signal. A repeat signal obeys `onRepeatSignal`. */\nexport const isExitSignal = (trigger: string): trigger is ExitSignal =>\n (EXIT_SIGNALS as readonly string[]).includes(trigger);\n\n/**\n * A message shape is a value of JSON that a message of the IPC channel can match. A string, a\n * number, a boolean or null matches an equal message. An object matches a message that has each of\n * its fields, and each value of the field matches. An array matches an array of the same length, item by item.\n */\nexport type MessageShape = string | number | boolean | null | readonly MessageShape[] | { readonly [field: string]: MessageShape };\n\n/** This function tells if a value is a message shape: a value of JSON, with no function and no undefined. */\nexport const isMessageShape = (value: unknown): value is MessageShape => {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return true;\n if (typeof value === \"number\") return Number.isFinite(value);\n if (Array.isArray(value)) return value.every(isMessageShape);\n if (typeof value !== \"object\") return false;\n const prototype = Object.getPrototypeOf(value) as unknown;\n return (prototype === Object.prototype || prototype === null) && Object.values(value).every(isMessageShape);\n};\n\n/** This function tells if a message of the IPC channel matches a shape. */\nexport const matchesMessage = (shape: MessageShape, message: unknown): boolean => {\n if (shape === null || typeof shape !== \"object\") return Object.is(shape, message);\n if (Array.isArray(shape)) {\n const items: readonly MessageShape[] = shape;\n return Array.isArray(message) && message.length === items.length && items.every((item, at) => matchesMessage(item, message[at]));\n }\n if (message === null || typeof message !== \"object\" || Array.isArray(message)) return false;\n const fields = message as Readonly<Record<string, unknown>>;\n return Object.entries(shape).every(([field, value]) => Object.hasOwn(fields, field) && matchesMessage(value, fields[field]));\n};\n\n/**\n * A process port is the part of the process that the runtime uses: its exit triggers, its output\n * and its exit. The runtime owns the handlers, because Node as PID 1 without a handler ignores\n * SIGTERM. Only the runtime ends the process, and library code does not. A test gives a fake port,\n * sends triggers, and reads the exit code.\n */\nexport interface ProcessPort {\n /**\n * This method adds a handler for a trigger, and gives the function that removes it. The runtime\n * asks for a process trigger only when the declaration opts in to it. For `ipc-message`, the\n * handler gets each message of the IPC channel, and the runtime matches it.\n */\n on(trigger: ExitTrigger, handler: (message?: unknown) => void): () => void;\n /**\n * This method writes each buffered line of the output, and its promise ends when the output is\n * written. The stage `flush the output` uses it, in the cap of that stage.\n */\n flush?(): Promise<void> | void;\n /**\n * This method keeps the process alive, and gives the function that releases it. The lifecycle\n * holds its process from its start to its exit, as a listening socket does. Thus a process whose\n * timers do not keep it alive does not end in the middle of its work. It keeps its teardown and its exit code.\n */\n hold?(): () => void;\n /** This method ends the process with a code: the code of the exit request, 1 after an error, or 0. */\n exit(code: number): void;\n}\n\n/** A host stream is the part of a stream of Node that the port uses. */\nexport interface HostStream {\n readonly writable?: boolean;\n readonly destroyed?: boolean;\n readonly readableEnded?: boolean;\n write(chunk: string, done: (error?: unknown) => void): boolean;\n on(event: string, handler: () => void): unknown;\n off(event: string, handler: () => void): unknown;\n}\n\n/** A process host is the part of the process of Node that the port uses. Its event `message` gives the message of the IPC channel. */\nexport interface ProcessHost {\n on(signal: string, handler: (message?: unknown) => void): unknown;\n off(signal: string, handler: (message?: unknown) => void): unknown;\n exit(code: number): unknown;\n readonly stdin?: HostStream | undefined;\n readonly stdout?: HostStream | undefined;\n readonly stderr?: HostStream | undefined;\n}\n\n/** This time is the interval of the timer of a hold, the most that a timer of Node accepts. */\nconst HOLD_INTERVAL = 0x7fffffff;\n\n/** This function adds a handler to some events of an emitter. The handler operates one time at most. */\nconst once = (emitter: HostStream | ProcessHost, events: readonly string[], handler: () => void): (() => void) => {\n let called = false;\n const fire = (): void => {\n if (called) return;\n called = true;\n handler();\n };\n for (const event of events) emitter.on(event, fire);\n return () => {\n for (const event of events) emitter.off(event, fire);\n };\n};\n\n/** This function gives a promise that ends when the data before it in a stream is written. */\nconst written = (stream: HostStream | undefined): Promise<void> =>\n new Promise<void>((resolve) => {\n if (stream === undefined || stream.destroyed === true || stream.writable === false) {\n resolve();\n return;\n }\n try {\n // the callback of an empty write comes after each write before it\n stream.write(\"\", () => resolve());\n } catch {\n resolve();\n }\n });\n\n/**\n * This function makes a process port on a host. `find` gives the host at each use, or undefined\n * when the platform has no process. Then the use throws.\n */\nexport const processPortOf = (find: () => ProcessHost | undefined): ProcessPort => {\n const hostProcess = (): ProcessHost => {\n const host = find();\n if (host === undefined) throw new Error(\"no process: give the runtime a process port\");\n return host;\n };\n return {\n on(trigger, handler) {\n const host = hostProcess();\n if (trigger === \"stdin-close\") {\n const input = host.stdin;\n if (input === undefined) return () => {};\n // an input that ended before the handler was added still starts the shutdown\n if (input.readableEnded === true) {\n let live = true;\n queueMicrotask(() => {\n if (live) handler();\n });\n return () => {\n live = false;\n };\n }\n return once(input, [\"end\", \"close\"], handler);\n }\n if (trigger === \"ipc-close\") return once(host, [\"disconnect\"], handler);\n if (trigger === \"ipc-message\") {\n // each message goes to the runtime, which matches it with the declared shapes\n const receive = (message?: unknown): void => handler(message);\n host.on(\"message\", receive);\n return () => {\n host.off(\"message\", receive);\n };\n }\n host.on(trigger, handler);\n return () => {\n host.off(trigger, handler);\n };\n },\n async flush() {\n const host = hostProcess();\n await Promise.all([written(host.stdout), written(host.stderr)]);\n },\n hold() {\n hostProcess();\n // one interval that keeps the event loop alive: its timer does nothing, and the release stops it\n const timer = setInterval(() => {}, HOLD_INTERVAL);\n let held = true;\n return () => {\n if (!held) return;\n held = false;\n clearInterval(timer);\n };\n },\n exit(code) {\n hostProcess().exit(code);\n },\n };\n};\n\n/** This port is the process of Node. */\nexport const nodeProcess: ProcessPort = processPortOf(() => (globalThis as { process?: ProcessHost }).process);\n\n/** An embedded process port records the exit code of a lifecycle that does not own its process. */\nexport interface EmbeddedProcess extends ProcessPort {\n /** This code is the code of the exit request of the lifecycle, or null before that request. */\n readonly exitCode: number | null;\n /** This promise ends with the exit code when the lifecycle asks for its exit. */\n readonly exited: Promise<number>;\n}\n\n/**\n * This function gives a process port for a lifecycle in a process that another part owns. That\n * part is a script, a test of an application, or a library entry. The port adds no handler of a signal or of\n * a trigger, it does not hold the process, and its `exit` only records the code. The caller stops\n * the lifecycle with `life.shutdown()`. A process with a service of its own gives its parts to\n * that service, and does not use this port.\n */\nexport const embeddedProcess = (): EmbeddedProcess => {\n let code: number | null = null;\n let resolve: (code: number) => void = () => {};\n const exited = new Promise<number>((done) => {\n resolve = done;\n });\n return {\n on() {\n // the owner of the process keeps its signals and triggers\n return () => {};\n },\n exit(requested) {\n if (code !== null) return;\n code = requested;\n resolve(requested);\n },\n get exitCode() {\n return code;\n },\n exited,\n };\n};\n","import type { Operation } from \"./operation.ts\";\nimport { operationProblems } from \"./operation.ts\";\n\n/**\n * A route pattern matches the routes of a controller that its exact routes do not name. A\n * registry that changes while the service operates, for example a registry of procedures, thus\n * needs no list of routes before the start. The syntax of a pattern:\n * - `*` matches each text, also an empty text and a text with `/`. The pattern `*` alone matches\n * each route.\n * - `:name` matches a text of one character or more without `/`, and gives it in `params.name`.\n * - Each other character matches itself.\n *\n * The declaration names the operations that a request of the pattern can be. Each operation\n * declares its idempotency, as a route does. A function picks the operation of each request.\n */\nexport interface RoutePattern {\n readonly pattern: string;\n /** These are the operations that a request of the pattern can be, by name. */\n readonly operations: Readonly<Record<string, Operation>>;\n}\n\n/** A route request is what the function of a pattern gets for one request. */\nexport interface RouteRequest {\n readonly controller: string;\n readonly route: string;\n /** These are the texts of the `:name` parts of the pattern, by name. */\n readonly params: Readonly<Record<string, string>>;\n /** These are the texts of the `*` parts of the pattern, in their sequence. */\n readonly wildcards: readonly string[];\n /** This value is the detail that the transport gives with the request, or undefined. */\n readonly detail: unknown;\n}\n\n/**\n * An operation choice gives the name of the operation of one request: one of the operations that\n * the pattern declares. Thus the function decides the idempotency of each request, and the\n * declaration keeps each window of a keyed operation as data.\n */\nexport type OperationOf = (request: RouteRequest) => string;\n\n/** A compiled pattern matches a route, and gives the parts of the route that it matched. */\nexport interface CompiledPattern {\n readonly pattern: string;\n match(route: string): { readonly params: Record<string, string>; readonly wildcards: string[] } | null;\n}\n\nconst NAME = /^[A-Za-z_][A-Za-z0-9_]*/;\n\n/** This function gives the problems of the syntax of a pattern: an empty pattern, a part without a name, or a name two times. */\nexport const patternProblems = (owner: string, pattern: string): string[] => {\n const problems: string[] = [];\n if (pattern.length === 0) problems.push(`${owner} has an empty route pattern`);\n const names = new Set<string>();\n for (let at = 0; at < pattern.length; at += 1) {\n if (pattern[at] !== \":\") continue;\n const name = NAME.exec(pattern.slice(at + 1))?.[0];\n if (name === undefined) {\n problems.push(`${owner}'s pattern ${pattern} has a \":\" without a name at ${at}`);\n continue;\n }\n if (names.has(name)) problems.push(`${owner}'s pattern ${pattern} names :${name} two times`);\n names.add(name);\n at += name.length;\n }\n return problems;\n};\n\n/** This function gives the problems of a pattern and of each of its operations, which `describe()` refuses. */\nexport const routePatternProblems = (owner: string, declared: RoutePattern): string[] => {\n const problems = patternProblems(owner, declared.pattern);\n const names = Object.keys(declared.operations);\n if (names.length === 0) problems.push(`${owner}'s pattern ${declared.pattern} declares no operation`);\n for (const name of names)\n problems.push(...operationProblems(owner, `${declared.pattern} (${name})`, declared.operations[name]!));\n return problems;\n};\n\n/** This function compiles a pattern to a matcher. The match must cover the whole route. */\nexport const compilePattern = (pattern: string): CompiledPattern => {\n const kinds: Array<{ kind: \"param\"; name: string } | { kind: \"wildcard\" }> = [];\n let source = \"^\";\n for (let at = 0; at < pattern.length; at += 1) {\n const char = pattern[at]!;\n if (char === \"*\") {\n source += \"([\\\\s\\\\S]*)\";\n kinds.push({ kind: \"wildcard\" });\n continue;\n }\n if (char === \":\") {\n const name = NAME.exec(pattern.slice(at + 1))?.[0];\n if (name !== undefined) {\n source += \"([^/]+)\";\n kinds.push({ kind: \"param\", name });\n at += name.length;\n continue;\n }\n }\n source += char.replace(/[.*+?^${}()|[\\]\\\\/]/g, \"\\\\$&\");\n }\n const matcher = new RegExp(`${source}$`);\n return {\n pattern,\n match(route) {\n const found = matcher.exec(route);\n if (found === null) return null;\n const params: Record<string, string> = {};\n const wildcards: string[] = [];\n kinds.forEach((part, index) => {\n const text = found[index + 1] ?? \"\";\n if (part.kind === \"param\") params[part.name] = text;\n else wildcards.push(text);\n });\n return { params, wildcards };\n },\n };\n};\n","import { quantity } from \"@mark1russell7/quantity\";\nimport type { Clock } from \"./clock.ts\";\nimport type { Controller } from \"./description.ts\";\nimport type { Operation } from \"./operation.ts\";\nimport { mayReissue } from \"./operation.ts\";\nimport type { CompiledPattern, OperationOf } from \"./routes.ts\";\nimport { compilePattern } from \"./routes.ts\";\n\n/**\n * A request end is the one final result of the stream of a request. Its count `delivered` is the\n * number of items that the stream gave before it. An end after the first item is in-band. The\n * transport sent its answer, thus it writes the end as the last line of the stream, not as a status.\n * - `done`: the work gave each of its items.\n * - `failed`: the work failed for a cause of its own. Before the first item, the adapter answers it\n * as it answers any error of the route.\n * - `refused`: the service did not admit the request. A refused request did not start, thus its\n * caller can send it again: 503, retryable.\n * - `cut`: the shutdown stopped the request. Before the first item, a route whose callers can send\n * it again answers 503, retryable, and each other route answers 500. After the first item, the\n * status is null, and the end is in-band.\n */\nexport type RequestEnd =\n | { readonly kind: \"done\"; readonly delivered: number }\n | { readonly kind: \"failed\"; readonly error: unknown; readonly delivered: number }\n | {\n readonly kind: \"refused\";\n readonly status: 503;\n readonly retryable: true;\n readonly cause: string;\n readonly delivered: 0;\n }\n | {\n readonly kind: \"cut\";\n readonly status: 503 | 500 | null;\n readonly retryable: boolean;\n readonly cause: string;\n readonly delivered: number;\n };\n\n/** A request event is one event of the stream of a request: an item, or the one end, which comes last. */\nexport type RequestEvent<T> = { readonly kind: \"item\"; readonly value: T } | RequestEnd;\n\n/**\n * A request stream is what a request comes to: its items, then one end. A unary work gives a stream\n * of one item. The stream gives an item only when its reader asks for the next event. Thus a slow\n * reader slows the work, and the request stays in flight until the work ends. When the reader\n * stops before the end, the work gets its abort and the `return()` of its iterator.\n */\nexport interface RequestStream<T> extends AsyncIterable<RequestEvent<T>> {\n /** This method reads the whole stream, and gives its items and its end. */\n collect(): Promise<{ readonly items: readonly T[]; readonly end: RequestEnd }>;\n}\n\n/**\n * A request work is what a request function gives: one value, or a stream of values. A work that\n * gives an async iterable is a stream, also through a promise. Each other value is a stream of one.\n */\nexport type RequestWork<T> = T | PromiseLike<T> | AsyncIterable<T> | PromiseLike<AsyncIterable<T>>;\n\n/** A request function does the work of one request. It receives a signal that the shutdown aborts. */\nexport type RequestFn<T> = (signal: AbortSignal) => RequestWork<T>;\n\n/** These options go with one request. */\nexport interface RequestOptions {\n /** This value goes to the function of a route pattern, for example the metadata of a procedure. */\n readonly detail?: unknown;\n}\n\n/** A tracker admits requests, counts the requests in flight, and ends what the shutdown cuts. */\nexport interface Tracker {\n request<T>(controller: string, route: string, work: RequestFn<T>, options?: RequestOptions): RequestStream<T>;\n inFlight(controller?: string): number;\n /** This method refuses each later request. */\n stopIntake(): void;\n /** This method aborts the signal of each request in flight, and ends each stream through `return()`: the cooperative abort of the drain. */\n cooperativeAbort(): void;\n /** This method waits until no request is in flight, or until `deadline`. Then it cuts each request that is left. */\n drain(deadline: number): Promise<void>;\n}\n\ninterface InFlight {\n readonly controller: string;\n /** This function aborts the work, and ends its iterator through `return()`. */\n readonly cooperative: () => void;\n /** This function ends the request with a cut, one time. */\n readonly cut: (cause: string) => void;\n}\n\nconst isAsyncIterable = (value: unknown): value is AsyncIterable<unknown> =>\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === \"function\";\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { then?: unknown }).then === \"function\";\n\n/** This function gives a stream of events from a function that gives the next event. */\nconst streamOf = <T>(next: () => Promise<RequestEvent<T> | null>, stop: () => void): RequestStream<T> => {\n let chain: Promise<unknown> = Promise.resolve();\n const iterator: AsyncIterator<RequestEvent<T>> = {\n next() {\n // a reader that asks again before an answer gets the events in their sequence\n const step = chain.then(next).then((event): IteratorResult<RequestEvent<T>> =>\n event === null ? { value: undefined, done: true } : { value: event, done: false },\n );\n chain = step.catch(() => {});\n return step;\n },\n return() {\n stop();\n return Promise.resolve({ value: undefined, done: true });\n },\n };\n return {\n [Symbol.asyncIterator]: () => iterator,\n async collect() {\n const items: T[] = [];\n for (;;) {\n const step = await iterator.next();\n if (step.done === true) throw new Error(\"the stream ended without its end\");\n if (step.value.kind === \"item\") items.push(step.value.value);\n else return { items, end: step.value };\n }\n },\n };\n};\n\n/**\n * This function makes a tracker. `refuses` gives the reason that the service refuses a new request\n * for a controller at this time, or null when it admits it. `choices` gives the function of each\n * route pattern, by controller and by pattern.\n */\nexport const tracker = (\n controllers: readonly Controller[],\n clock: Clock,\n refuses: (controller: string) => string | null,\n choices: ReadonlyMap<string, ReadonlyMap<string, OperationOf>> = new Map(),\n): Tracker => {\n const byName = new Map(\n controllers.map((controller) => [\n controller.name,\n {\n controller,\n patterns: (controller.patterns ?? []).map((declared) => ({ declared, compiled: compilePattern(declared.pattern) as CompiledPattern })),\n },\n ]),\n );\n const flights = new Set<InFlight>();\n const idle = new Set<() => void>();\n let intake = true;\n\n /** This function gives the operation of a request: its exact route, else the first pattern that matches it. */\n const operationOf = (controller: string, route: string, detail: unknown): Operation => {\n const held = byName.get(controller);\n if (held === undefined) throw new Error(`there is no controller ${controller}`);\n const exact = held.controller.routes[route];\n if (exact !== undefined) return exact;\n for (const { declared, compiled } of held.patterns) {\n const found = compiled.match(route);\n if (found === null) continue;\n const names = Object.keys(declared.operations);\n const choose = choices.get(controller)?.get(declared.pattern);\n const name = choose === undefined ? names[0]! : choose({ controller, route, ...found, detail });\n const operation = declared.operations[name];\n if (operation === undefined)\n throw new Error(`the pattern ${declared.pattern} of ${controller} declares no operation ${String(name)} for ${route}`);\n return operation;\n }\n // a route that nobody declared has no idempotency: the runtime has no defaults\n throw new Error(`controller ${controller} does not declare the route ${route}`);\n };\n\n const settle = (flight: InFlight): void => {\n if (!flights.delete(flight)) return;\n if (flights.size === 0) for (const done of [...idle]) done();\n };\n\n /** This function starts the work of an admitted request, and gives its stream. */\n const open = <T>(controller: string, operation: Operation, work: RequestFn<T>): RequestStream<T> => {\n const started = clock.now();\n const abort = new AbortController();\n let delivered = 0;\n let end: RequestEnd | null = null;\n let ended = false;\n let returned = false;\n let source: AsyncIterator<T> | null = null;\n // a unary work keeps its value until the reader asks for it\n let unary: { readonly value: T } | null = null;\n let interrupt: () => void = () => {};\n const interrupted = new Promise<\"interrupted\">((resolve) => {\n interrupt = () => resolve(\"interrupted\");\n });\n\n const cutEnd = (cause: string): RequestEnd => {\n const since = quantity(Math.max(0, clock.now() - started) / 1000, \"s\");\n const retryable = mayReissue(operation, since);\n return { kind: \"cut\", status: delivered > 0 ? null : retryable ? 503 : 500, retryable, cause, delivered };\n };\n /** This function ends the work of the request: the end is known, and the request leaves the flights. */\n const finish = (given: RequestEnd): void => {\n if (end !== null) return;\n end = given;\n settle(flight);\n interrupt();\n };\n /** This function ends the work after a throw: a failure after the shutdown aborted it is a cut. */\n const failed = (error: unknown): void =>\n finish(abort.signal.aborted ? cutEnd(\"the shutdown aborted it, and it failed\") : { kind: \"failed\", error, delivered });\n const closeSource = (): void => {\n if (source === null || returned) return;\n returned = true;\n try {\n void Promise.resolve(source.return?.()).catch(() => {});\n } catch {\n // an iterator whose return() throws has ended\n }\n };\n const flight: InFlight = {\n controller,\n cooperative: () => {\n abort.abort(new Error(\"the cooperative abort of the drain\"));\n closeSource();\n },\n cut: (cause) => {\n abort.abort(new Error(cause));\n finish(cutEnd(cause));\n closeSource();\n },\n };\n flights.add(flight);\n\n /** This function takes the result of the work: a stream, or one value. */\n const take = (result: unknown): void => {\n if (end !== null) return;\n if (isAsyncIterable(result)) {\n source = (result as AsyncIterable<T>)[Symbol.asyncIterator]();\n // a stream that comes after the cooperative abort ends at once\n if (abort.signal.aborted) closeSource();\n } else {\n unary = { value: result as T };\n // the unary work has ended: its value waits for the reader\n settle(flight);\n }\n };\n let ready: Promise<void>;\n try {\n const result = work(abort.signal);\n if (isAsyncIterable(result) || !isPromiseLike(result)) {\n take(result);\n ready = Promise.resolve();\n } else ready = Promise.resolve(result).then(take, failed);\n } catch (error) {\n failed(error);\n ready = Promise.resolve();\n }\n\n const next = async (): Promise<RequestEvent<T> | null> => {\n if (ended) return null;\n if (end === null) await Promise.race([ready, interrupted]);\n if (end === null && unary !== null) {\n const { value } = unary;\n unary = null;\n delivered = 1;\n end = { kind: \"done\", delivered };\n return { kind: \"item\", value };\n }\n if (end === null && source !== null) {\n const pending = source.next();\n let step: IteratorResult<T> | \"interrupted\";\n try {\n step = await Promise.race([pending, interrupted]);\n } catch (error) {\n failed(error);\n step = \"interrupted\";\n }\n if (step !== \"interrupted\") {\n if (step.done !== true) {\n delivered += 1;\n return { kind: \"item\", value: step.value };\n }\n // a stream that ends after the abort of the shutdown is a cut\n finish(abort.signal.aborted ? cutEnd(\"the shutdown ended the stream\") : { kind: \"done\", delivered });\n }\n }\n ended = true;\n return end!;\n };\n const stop = (): void => {\n // the reader stopped before the end: the work stops too\n if (end === null) {\n abort.abort(new Error(\"the reader stopped the stream\"));\n finish({ kind: \"done\", delivered });\n closeSource();\n }\n ended = true;\n };\n return streamOf(next, stop);\n };\n\n return {\n request<T>(controller: string, route: string, work: RequestFn<T>, options: RequestOptions = {}) {\n const operation = operationOf(controller, route, options.detail);\n const refusal = intake ? refuses(controller) : \"the service stopped its intake\";\n if (refusal !== null) {\n let given = false;\n const refused: RequestEnd = { kind: \"refused\", status: 503, retryable: true, cause: refusal, delivered: 0 };\n return streamOf<T>(\n () => {\n if (given) return Promise.resolve(null);\n given = true;\n return Promise.resolve(refused);\n },\n () => {\n given = true;\n },\n );\n }\n return open(controller, operation, work);\n },\n inFlight(controller) {\n let count = 0;\n for (const flight of flights) if (controller === undefined || flight.controller === controller) count += 1;\n return count;\n },\n stopIntake() {\n intake = false;\n },\n cooperativeAbort() {\n for (const flight of [...flights]) flight.cooperative();\n },\n drain(deadline) {\n if (flights.size === 0) return Promise.resolve();\n return new Promise<void>((resolve) => {\n let finished = false;\n const done = (): void => {\n if (finished) return;\n finished = true;\n idle.delete(done);\n cancel();\n resolve();\n };\n idle.add(done);\n const cancel = clock.after(Math.max(0, deadline - clock.now()), () => {\n for (const flight of [...flights]) flight.cut(\"the drain reached its deadline\");\n done();\n });\n });\n },\n };\n};\n","import type { Extent } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { CooperativeFloor, Phase, ServiceDescription } from \"./description.ts\";\nimport type { MachineName } from \"./events.ts\";\nimport type { Health, Runtime, StartOptions } from \"./health.ts\";\nimport type { ExitTrigger, ProcessPort } from \"./process.ts\";\nimport { EXIT_SIGNALS, isExitCode, isExitSignal, matchesMessage, nodeProcess } from \"./process.ts\";\nimport type { RequestFn, RequestOptions, RequestStream } from \"./requests.ts\";\nimport { tracker } from \"./requests.ts\";\nimport type { OperationOf } from \"./routes.ts\";\n\n/**\n * A transport is a source of work: a server, a consumer or a worker. Each has one contract. It\n * starts, stops its intake, and drains to a deadline without a throw. It counts its work in flight,\n * and it closes. A second close has no effect.\n */\nexport interface TransportImpl {\n /**\n * This method starts the transport. The lifecycle is the object that `run()` gives at the end of\n * the startup. Its request tracking operates from the start: a request before the startup ends\n * gets a retryable refusal, and `keepAlive()` is false. Do not wait for `life.started` here,\n * because the startup waits for this method.\n */\n start(signal: AbortSignal, life: Lifecycle): Promise<void> | void;\n stopIntake(): Promise<void> | void;\n /**\n * This method lets the work in flight end until `deadline` (milliseconds on the monotonic\n * clock). The signal is the cooperative abort, which comes before the deadline.\n */\n drain(deadline: number, signal: AbortSignal): Promise<void> | void;\n inFlight(): number;\n close(): Promise<void> | void;\n}\n\n/** A dependency handle connects to a dependency at the start, and closes the connection at the end. */\nexport interface DependencyHandle {\n connect(signal: AbortSignal): Promise<void> | void;\n close(): Promise<void> | void;\n}\n\n/**\n * A health server answers the probes, on its own port. It starts first, thus the probes answer\n * while the dependencies connect, and it closes last.\n */\nexport interface HealthServer {\n listen(health: Health): Promise<void> | void;\n close(): Promise<void> | void;\n}\n\n/** A phase context is what a phase gives its work: its deadline, its signal and the clock. */\nexport interface PhaseContext {\n /** This time is the end of the cap of the phase, in milliseconds on the monotonic clock. */\n readonly deadline: number;\n /** This signal aborts at the end of the cap of the phase. */\n readonly signal: AbortSignal;\n readonly clock: Clock;\n}\n\n/** A phase work is a step of the shutdown that an owner adds to a phase. */\nexport type PhaseWork = (context: PhaseContext) => Promise<void> | void;\n\n/**\n * These are the stages of the shutdown, in their sequence. A declared phase with one of these\n * names gets the work of the runtime for its stage. A phase with another name gets only the work of\n * its owners.\n * - `fail readiness`: readiness fails at the start of the shutdown. This phase then holds for its\n * cap, while the endpoints of the platform remove the service.\n * - `stop intake`: each transport stops its intake, and new requests get a retryable 503.\n * - `drain`: the transports and the requests in flight end, until the cap. The cooperative abort\n * comes before the end of the cap, by the cooperative window.\n * - `close transports`: each transport closes.\n * - `stop the poller`: each check and watchdog stops. Then the signal of the service aborts.\n * - `tear down dependencies`: each dependency closes, in the reverse sequence of its connection.\n * - `close the health server`: the probes stop.\n * - `flush the output`: the work of the owners of this phase ends, and then the process port\n * writes the buffered output. Without this phase, the process exits without a wait.\n */\nexport const STAGES = [\n \"fail readiness\",\n \"stop intake\",\n \"drain\",\n \"close transports\",\n \"stop the poller\",\n \"tear down dependencies\",\n \"close the health server\",\n \"flush the output\",\n] as const;\n\nexport type Stage = (typeof STAGES)[number];\n\n/** This function gives the place of a stage in the sequence, or -1 for a phase of another name. */\nexport const stageRank = (name: string): number => (STAGES as readonly string[]).indexOf(name);\n\n/** The signal of the service aborts after the poller stops, and before the dependencies close. */\nconst ABORT_AFTER = stageRank(\"stop the poller\");\n\n/**\n * This function gives the time of the cooperative abort, in milliseconds after the drain starts. It\n * is the cap less the cooperative window. With the floor `half`, it is not less than half the cap,\n * and a window without a bound gives half the cap. With the floor `none`, it is not less than 0.\n */\nexport const cooperativeAbortAt = (cap: number, window: Extent, floor: CooperativeFloor = \"half\"): number => {\n const before = window.value === \"infinite\" ? Number.POSITIVE_INFINITY : valueIn(window, \"ms\");\n return Math.max(cap - before, floor === \"none\" ? 0 : cap / 2);\n};\n\n/** These options run the lifecycle. Without them, it uses the real clock and the process of Node. */\nexport interface RunOptions extends StartOptions {\n readonly process?: ProcessPort | undefined;\n}\n\n/** These options go with a request for the shutdown. */\nexport interface ShutdownOptions {\n /**\n * This code is the exit code that the work of the process gives, a whole number from 0 to 255. The\n * first exit request with a code sets it. A code of 0 lets an error make the exit code 1.\n */\n readonly code?: number | undefined;\n}\n\n/** A lifecycle state tells where the service is in its life. */\nexport type LifecycleState = \"starting\" | \"running\" | \"draining\" | \"exited\";\n\n/** The lifecycle of a running service. */\nexport interface Lifecycle {\n readonly health: Health;\n readonly state: LifecycleState;\n /** This code is the exit code, or null before the exit. */\n readonly exitCode: number | null;\n /** These texts are the errors of the lifecycle. An error makes the exit code 1, unless an exit request gives another code. */\n readonly errors: readonly string[];\n /** This promise ends when the startup ends: the service runs, or its startup failed. */\n readonly started: Promise<void>;\n /** This promise gives the exit code when the shutdown ends. */\n readonly done: Promise<number>;\n /** This signal aborts after the poller stops: the background work of the service stops with it. */\n readonly signal: AbortSignal;\n /**\n * This method asks for the shutdown, as an exit signal does. A second request does not start a\n * second shutdown. It can give the exit code, when no request gave one before.\n */\n shutdown(cause?: string, options?: ShutdownOptions): Promise<number>;\n /**\n * This method does one request of a controller, on a route or a route pattern that the controller\n * declares. It gives the stream of the request: each item of the work, then one end. The service\n * refuses the request while it cannot take new work, and the shutdown can cut it. An undeclared\n * route throws, because it has no idempotency.\n */\n request<T>(controller: string, route: string, work: RequestFn<T>, options?: RequestOptions): RequestStream<T>;\n inFlight(controller?: string): number;\n /**\n * This method tells if a response can keep its connection open. It is false while the service is\n * not ready, thus each response then closes its connection.\n */\n keepAlive(): boolean;\n}\n\n/** The parts that the builder gives the lifecycle, beside the declaration. */\nexport interface Components {\n readonly transports: ReadonlyMap<string, TransportImpl>;\n readonly dependencies: ReadonlyMap<string, DependencyHandle>;\n readonly healthServer: HealthServer | null;\n readonly phaseWork: ReadonlyMap<string, readonly PhaseWork[]>;\n /** These are the functions of the route patterns, by controller and by pattern. */\n readonly choices?: ReadonlyMap<string, ReadonlyMap<string, OperationOf>> | undefined;\n /** This function stops the parts that the poller stage stops beside the checks: the watchdogs. */\n readonly stopPollers: () => void;\n}\n\nconst message = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * This function gives the problems of a declaration that the lifecycle cannot start: a stage with\n * work and no declared phase. The runtime has no defaults, thus a transport without a drain phase\n * has no time to drain.\n */\nexport const lifecycleProblems = (description: ServiceDescription, components: Components): string[] => {\n const declared = new Set(description.shutdown.phases.map((phase) => phase.name));\n const needs = (stage: Stage, why: string): string[] =>\n declared.has(stage) ? [] : [`${description.name} has ${why}, thus it declares the phase \"${stage}\"`];\n const problems: string[] = [];\n for (const transport of description.transports)\n if (!components.transports.has(transport.name))\n problems.push(`transport ${transport.name} has no implementation: the runtime has no defaults`);\n if (components.transports.size > 0 || description.controllers.length > 0) {\n problems.push(...needs(\"stop intake\", \"transports or controllers\"));\n problems.push(...needs(\"drain\", \"transports or controllers\"));\n }\n if (components.transports.size > 0) problems.push(...needs(\"close transports\", \"transports\"));\n if (description.checks.length > 0) problems.push(...needs(\"stop the poller\", \"checks\"));\n if (components.dependencies.size > 0) problems.push(...needs(\"tear down dependencies\", \"dependency handles\"));\n if (components.healthServer !== null) problems.push(...needs(\"close the health server\", \"a health server\"));\n return problems;\n};\n\n/**\n * This function starts the lifecycle of a service. The startup has a sequence: the health server\n * first, then each dependency, then each transport, and the startup gate last. A trigger during the\n * startup gets its shutdown after the startup ends. The shutdown does the declared phases in their\n * sequence, each one capped. Only the lifecycle ends the process. Its exit code is the code of the\n * exit request, else 1 after an error, else 0.\n */\nexport const lifecycle = (\n description: ServiceDescription,\n runtime: Runtime,\n components: Components,\n options: RunOptions = {},\n /** This function receives the lifecycle before the startup begins. */\n bind: (life: Lifecycle) => void = () => {},\n): Lifecycle => {\n const clock = options.clock ?? realClock;\n const port = options.process ?? nodeProcess;\n const record = (machine: MachineName, from: string, to: string, on: string, detail?: string): void =>\n options.record?.({\n at: clock.now(),\n machine,\n instance: description.name,\n from,\n to,\n on,\n ...(detail === undefined ? {} : { detail }),\n });\n const service = new AbortController();\n const errors: string[] = [];\n const exitCodes = description.shutdown.exitCodes ?? {};\n const repeatPolicy = description.shutdown.onRepeatSignal;\n let state: LifecycleState = \"starting\";\n let exitCode: number | null = null;\n // the code of the first exit request that gives one\n let requested: number | undefined;\n let intakeStopped = false;\n let shutdownStarted = false;\n let failedStartup = false;\n // the exit manager: running, stopping, exited\n let exitState = \"running\";\n const moveExit = (to: string, on: string, detail?: string): void => {\n record(\"exit\", exitState, to, on, detail);\n exitState = to;\n };\n const fail = (cause: string): void => {\n errors.push(cause);\n // after an exit, the process has ended: the exit manager does not move again\n if (exitState !== \"exited\") record(\"exit\", exitState, exitState, \"error\", cause);\n };\n\n const requests = tracker(description.controllers, clock, (controller) => {\n if (state === \"starting\") return \"the service has not started\";\n if (state === \"exited\") return \"the service has exited\";\n // while it drains and before its intake stops, the service still serves: the platform can\n // still route a request to it until its endpoints update\n if (state === \"draining\") return null;\n return runtime.verdict().controllers[controller] === true ? null : `controller ${controller} is not ready`;\n }, components.choices);\n\n let finish: (code: number) => void = () => {};\n const done = new Promise<number>((resolve) => {\n finish = resolve;\n });\n // what started, thus what the shutdown stops\n let healthListening = false;\n const connected: Array<[string, DependencyHandle]> = [];\n const startedTransports: Array<[string, TransportImpl]> = [];\n // the startup exists before any part starts: a transport that asks for the shutdown in its start waits for it\n let startupEnded: () => void = () => {};\n const startup = new Promise<void>((resolve) => {\n startupEnded = resolve;\n });\n let offs: Array<() => void> = [];\n // the hold of the process, from the start of the lifecycle to its exit\n let release: () => void = () => {};\n\n /** This function ends the process with a code, one time, and removes each handler of a trigger and the hold. */\n const end = (code: number, on: string): void => {\n state = \"exited\";\n exitCode = code;\n for (const off of offs) off();\n offs = [];\n moveExit(\"exited\", on, `exit ${code}`);\n finish(code);\n // the hold ends at the exit, not at the stop of the intake: the drain and the teardown still need the process\n release();\n port.exit(code);\n };\n\n /**\n * This function receives a trigger of the process: the first one starts the shutdown. The cause\n * names the trigger, and a message that stands for a signal tells it.\n */\n const triggered = (trigger: ExitTrigger, cause: string = trigger): void => {\n if (exitState === \"exited\") return;\n if (shutdownStarted || exitState === \"stopping\") {\n // a signal while the shutdown runs obeys the declared policy. Another trigger, for example the\n // end of stdin after a SIGTERM, has no effect\n if (isExitSignal(trigger) && repeatPolicy === \"exit\") {\n fail(`${cause} came again while the shutdown ran, and the declaration exits at once`);\n end(1, \"exit.repeat\");\n return;\n }\n record(\"exit\", exitState, exitState, \"exit.repeat\", cause);\n return;\n }\n const code = exitCodes[trigger];\n void shutdown(cause, code === undefined ? {} : { code });\n };\n const messages = description.shutdown.messages ?? [];\n /** This function receives a message of the IPC channel. The first declared shape that it matches gives its trigger. */\n const received = (message: unknown): void => {\n const found = messages.find((each) => matchesMessage(each.match, message));\n if (found === undefined) return;\n if (found.as === undefined) triggered(\"ipc-message\");\n else triggered(found.as, `${found.as} (a message of the IPC channel)`);\n };\n\n /** This function does the work of one phase, until its cap. It gives true when the work ended in time. */\n const runPhase = async (phase: Phase, hold: boolean, work: ReadonlyArray<(context: PhaseContext) => Promise<void> | void>): Promise<boolean> => {\n const cap = valueIn(phase.cap, \"ms\");\n const deadline = clock.now() + cap;\n const capped = new AbortController();\n const context: PhaseContext = { deadline, signal: capped.signal, clock };\n let pending = work.length;\n const all = Promise.all(\n work.map(async (each) => {\n try {\n await each(context);\n } catch (error) {\n fail(`the phase ${phase.name} failed: ${message(error)}`);\n } finally {\n pending -= 1;\n }\n }),\n );\n let cancelCap: Cancel = () => {};\n const end = new Promise<\"cap\">((resolve) => {\n cancelCap = clock.after(cap, () => resolve(\"cap\"));\n });\n const first = await Promise.race([all.then(() => \"work\" as const), end]);\n if (first === \"work\" && hold) await end;\n cancelCap();\n capped.abort(new Error(`the phase ${phase.name} reached its cap`));\n return pending === 0;\n };\n\n async function shutdown(cause = \"the service asked for it\", request: ShutdownOptions = {}): Promise<number> {\n if (request.code !== undefined && !isExitCode(request.code))\n throw new Error(`${description.name}: the exit code ${request.code} is not a whole number from 0 to 255`);\n if (exitState === \"exited\") return done;\n if (request.code !== undefined && requested === undefined) requested = request.code;\n if (shutdownStarted) {\n if (exitState === \"stopping\") record(\"exit\", exitState, exitState, \"exit.repeat\", cause);\n return done;\n }\n shutdownStarted = true;\n if (exitState === \"running\") moveExit(\"stopping\", \"exit.request\", cause);\n // a trigger during the startup gets its shutdown after the startup ends\n await startup;\n // a repeat signal can end the process while the startup ends: then only the timers stop\n if (exitState === \"exited\") {\n runtime.stop();\n components.stopPollers();\n return exitCode!;\n }\n state = \"draining\";\n runtime.drain();\n let drainState = \"running\";\n const moveDrain = (to: string, on: string, detail?: string): void => {\n record(\"drain\", drainState, to, on, detail);\n drainState = to;\n };\n const abortService = (): void => {\n if (service.signal.aborted) return;\n service.abort(new Error(\"the service stopped\"));\n record(\"drain\", drainState, drainState, \"signal.abort\");\n };\n const phases = description.shutdown.phases;\n let on = \"exit.request\";\n for (const phase of phases) {\n // after a repeat signal ends the process, no phase starts\n if (exitState === \"exited\") break;\n const rank = stageRank(phase.name);\n moveDrain(phase.name, on);\n if (rank > ABORT_AFTER) abortService();\n const work: Array<(context: PhaseContext) => Promise<void> | void> = [];\n const owned = components.phaseWork.get(phase.name) ?? [];\n if (phase.name === \"stop intake\") {\n work.push(() => {\n intakeStopped = true;\n requests.stopIntake();\n });\n for (const [, impl] of startedTransports) work.push(() => impl.stopIntake());\n }\n // the cooperative abort of the drain: the cap less the window, not before the floor. It ends\n // with the phase, thus a drain that ends before it does not abort anything\n let cancelAbort: Cancel = () => {};\n if (phase.name === \"drain\") {\n const cap = valueIn(phase.cap, \"ms\");\n const cooperative = new AbortController();\n const fireAt = cooperativeAbortAt(cap, description.shutdown.cooperativeWindow, description.shutdown.cooperativeFloor);\n cancelAbort = clock.after(fireAt, () => {\n cooperative.abort(new Error(\"the cooperative abort of the drain\"));\n requests.cooperativeAbort();\n record(\"drain\", drainState, drainState, \"drain.cooperative-abort\");\n });\n work.push(({ deadline }) => requests.drain(deadline));\n for (const [, impl] of startedTransports)\n work.push(({ deadline }) => impl.drain(deadline, cooperative.signal));\n }\n if (phase.name === \"close transports\")\n for (const [, impl] of startedTransports) work.push(() => impl.close());\n if (phase.name === \"stop the poller\")\n work.push(() => {\n runtime.stop();\n components.stopPollers();\n });\n if (phase.name === \"tear down dependencies\")\n work.push(async () => {\n for (const [, handle] of [...connected].reverse()) await handle.close();\n });\n if (phase.name === \"close the health server\" && healthListening && components.healthServer !== null) {\n const server = components.healthServer;\n work.push(() => server.close());\n }\n if (phase.name === \"flush the output\")\n // the owners write their last output first (a log or a trace exporter), then the port writes it\n work.push(async (context) => {\n await Promise.all(\n owned.map(async (each) => {\n try {\n await each(context);\n } catch (error) {\n fail(`the phase ${phase.name} failed: ${message(error)}`);\n }\n }),\n );\n await port.flush?.();\n });\n else for (const each of owned) work.push(each);\n const inTime = await runPhase(phase, phase.name === \"fail readiness\", work);\n cancelAbort();\n if (!inTime) fail(`the phase ${phase.name} did not end in its cap of ${valueIn(phase.cap, \"s\")} s`);\n on = inTime ? \"phase.done\" : \"phase.cap\";\n }\n if (exitState !== \"exited\") moveDrain(\"done\", on);\n abortService();\n // a stage that the declaration does not name still stops: the checks, at the end\n runtime.stop();\n components.stopPollers();\n if (!intakeStopped) requests.stopIntake();\n // a repeat signal can end the process during the sequence: then it ended already\n if (exitState === \"exited\") return exitCode!;\n const code = requested !== undefined && requested !== 0 ? requested : errors.length > 0 ? 1 : 0;\n end(code, \"shutdown.done\");\n return code;\n }\n\n const life: Lifecycle = {\n health: runtime,\n get state() {\n return state;\n },\n get exitCode() {\n return exitCode;\n },\n get errors() {\n return [...errors];\n },\n started: startup,\n done,\n signal: service.signal,\n shutdown,\n request: (controller, route, work, request) => requests.request(controller, route, work, request),\n inFlight: (controller) => requests.inFlight(controller),\n keepAlive: () => state === \"running\" && runtime.verdict().ready,\n };\n\n bind(life);\n release = port.hold?.() ?? (() => {});\n offs = [...EXIT_SIGNALS, ...(description.shutdown.triggers ?? [])].map((trigger: ExitTrigger) =>\n port.on(trigger, trigger === \"ipc-message\" ? received : () => triggered(trigger)),\n );\n\n void (async (): Promise<void> => {\n const started = (what: string): void => record(\"gate\", \"starting\", \"starting\", \"component.started\", what);\n try {\n runtime.beginStartup();\n if (components.healthServer !== null) {\n await components.healthServer.listen(runtime);\n healthListening = true;\n started(\"the health server\");\n }\n for (const dependency of description.dependencies) {\n const handle = components.dependencies.get(dependency.name);\n if (handle === undefined) continue;\n await handle.connect(service.signal);\n connected.push([dependency.name, handle]);\n started(`dependency ${dependency.name}`);\n }\n for (const transport of description.transports) {\n const impl = components.transports.get(transport.name)!;\n await impl.start(service.signal, life);\n startedTransports.push([transport.name, impl]);\n started(`${transport.kind} ${transport.name}`);\n }\n await runtime.warmUp();\n if (state === \"starting\") state = \"running\";\n } catch (error) {\n const cause = `the startup failed: ${message(error)}`;\n failedStartup = true;\n runtime.failStartup(cause);\n fail(cause);\n if (exitState === \"running\") moveExit(\"stopping\", \"startup.fail\", cause);\n else if (exitState === \"stopping\") record(\"exit\", exitState, exitState, \"startup.fail\", cause);\n } finally {\n startupEnded();\n }\n })();\n // a failed startup shuts down what started. An exit request during the startup waits for it\n void startup.then(() => {\n if (failedStartup && !shutdownStarted && exitState !== \"exited\") void shutdown(\"the startup failed\");\n });\n\n return life;\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { Gate } from \"./description.ts\";\nimport type { Outcome, Trace } from \"./latch.ts\";\nimport type { Poll } from \"./timing.ts\";\n\n/**\n * A watchdog spec declares a watchdog of the event loop. The service declares it as a check whose\n * function the watchdog gives: the process's own wedge, which a liveness window reads.\n */\nexport interface WatchdogSpec {\n readonly name: string;\n /** This time is the interval of the tick of the watchdog. */\n readonly tick: Quantity;\n /** This time is the most that a tick can be late before the loop counts as blocked. */\n readonly threshold: Quantity;\n /** This gate is the policy that the check controls, or null for a check that only reports. */\n readonly gates: Gate | null;\n readonly poll: Poll;\n}\n\n/**\n * A watchdog measures how late its own tick comes. A blocked event loop delays each timer, thus a\n * tick that comes later than the threshold shows the block. Its states are `watching`, `blocked`\n * and `stopped`.\n */\nexport interface Watchdog {\n /** This function is the check: it fails when a tick since the last poll came late, or the loop is still blocked. */\n readonly check: () => Outcome;\n /** This time is the most that a tick was late, in milliseconds, since the start. */\n readonly worst: number;\n readonly blocked: boolean;\n stop(): void;\n}\n\n/** This function starts a watchdog on a clock. */\nexport const watchdog = (clock: Clock, spec: WatchdogSpec, trace?: Trace): Watchdog => {\n const tick = valueIn(spec.tick, \"ms\");\n const threshold = valueIn(spec.threshold, \"ms\");\n if (!(tick > 0)) throw new RangeError(`watchdog ${spec.name} ticks every ${tick} ms, not above zero`);\n let blocked = false;\n let stopped = false;\n let worst = 0;\n // the worst lateness since the last poll of the check\n let sincePoll = 0;\n let next: Cancel | null = null;\n\n const named = (): string => (stopped ? \"stopped\" : blocked ? \"blocked\" : \"watching\");\n const arm = (): void => {\n const due = clock.now() + tick;\n next = clock.after(tick, () => {\n next = null;\n if (stopped) return;\n const late = Math.max(0, clock.now() - due);\n worst = Math.max(worst, late);\n sincePoll = Math.max(sincePoll, late);\n const from = named();\n blocked = late > threshold;\n trace?.(from, named(), \"tick\");\n arm();\n });\n };\n arm();\n\n return {\n check: () => {\n const failed = blocked || sincePoll > threshold;\n sincePoll = 0;\n return failed ? \"error\" : \"ok\";\n },\n get worst() {\n return worst;\n },\n get blocked() {\n return blocked;\n },\n stop() {\n if (stopped) return;\n const from = named();\n stopped = true;\n next?.();\n next = null;\n trace?.(from, \"stopped\", \"stop\");\n },\n };\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { convertible, valueIn } from \"@mark1russell7/quantity\";\nimport type {\n Check,\n Controller,\n CooperativeFloor,\n Coupling,\n Dependency,\n ExitCodes,\n Gate,\n MessageTrigger,\n Phase,\n RepeatSignal,\n ServiceDescription,\n Transport,\n} from \"./description.ts\";\nimport { FORMAT } from \"./description.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { Health, Runtime, StartOptions } from \"./health.ts\";\nimport { healthRuntime } from \"./health.ts\";\nimport type {\n Components,\n DependencyHandle,\n HealthServer,\n Lifecycle,\n PhaseWork,\n RunOptions,\n TransportImpl,\n} from \"./lifecycle.ts\";\nimport { STAGES, lifecycle, lifecycleProblems, stageRank } from \"./lifecycle.ts\";\nimport type { Operation } from \"./operation.ts\";\nimport { operationProblems } from \"./operation.ts\";\nimport type { CheckFn } from \"./poller.ts\";\nimport type { ExitTrigger, ProcessTrigger } from \"./process.ts\";\nimport { EXIT_SIGNALS, PROCESS_TRIGGERS, isExitCode, isExitSignal, isMessageShape } from \"./process.ts\";\nimport type { Profile } from \"./profiles.ts\";\nimport type { OperationOf, RoutePattern } from \"./routes.ts\";\nimport { routePatternProblems } from \"./routes.ts\";\nimport type { Timing } from \"./timing.ts\";\nimport type { Watchdog, WatchdogSpec } from \"./watchdog.ts\";\nimport { watchdog } from \"./watchdog.ts\";\n\n/**\n * A service is composed with plain method uses before it starts. The builder is imperative, and\n * it holds static knowledge. The service does not use an `init` function that gives registrations.\n *\n * const svc = service(\"app\");\n * svc.dependency(\"weather\", {\n * system: null,\n * knobs: { request_timeout },\n * operations: { \"GET /v1/forecast\": { idempotent: true } },\n * });\n * svc.controller(\"forecast\").requires(\"weather\").route(\"GET /api/forecast\", { idempotent: true });\n * svc.check({ name: \"weather.round-trip\", dependency: \"weather\", … }, roundTrip);\n * svc.describe(); // the whole graph as data, with nothing started\n * const health = await svc.start();\n *\n * The graph has one source, thus its parts cannot disagree. A dependency or a check can join\n * after the start. It starts tripped, and the export is partial. The runtime has no defaults of\n * its own. Thus `describe()` refuses a service that does not declare a policy, its startup budget\n * or its shutdown, and it tells which. The shutdown includes what a repeat signal does.\n *\n * `start()` starts only the health runtime. `run()` starts the whole lifecycle: the startup in its\n * sequence, the exit signals, the capped phases of the shutdown, and the exit of the process.\n */\nexport interface ControllerBuilder {\n /** This method declares the dependencies that its routes need. The controller is ready only while they are ready. */\n requires(...dependencies: string[]): ControllerBuilder;\n /** This method declares a route that the controller serves, and if its callers can send it again. */\n route(route: string, operation: Operation): ControllerBuilder;\n /**\n * This method declares a route pattern, the operations that its requests can be, and the function\n * that picks the operation of each request. A pattern with one operation needs no function.\n */\n pattern(pattern: string, operations: Readonly<Record<string, Operation>>, operationOf?: OperationOf): ControllerBuilder;\n}\n\n/** A service builder composes a service, gives it as data, and starts it. */\nexport interface ServiceBuilder {\n readonly name: string;\n /** This method declares a dependency, and the handle that connects to it and closes it, if it has one. */\n dependency(name: string, spec: Omit<Dependency, \"name\">, handle?: DependencyHandle): ServiceBuilder;\n /** This method declares a server, and its implementation. `run()` needs the implementation. */\n server(name: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl): ServiceBuilder;\n consumer(name: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl): ServiceBuilder;\n worker(name: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl): ServiceBuilder;\n /** This method gives the server of the probes. It starts first and closes last. */\n healthServer(server: HealthServer): ServiceBuilder;\n /** This method adds work to a declared phase of the shutdown: the owner of the work registers it. */\n onPhase(phase: string, work: PhaseWork): ServiceBuilder;\n /** This method declares a watchdog of the event loop, as a check on the state of the process. */\n watchdog(spec: WatchdogSpec): ServiceBuilder;\n controller(name: string): ControllerBuilder;\n /** This method declares a check, and the function that measures its step. `start()` needs the function. */\n check(check: Check, run?: CheckFn): ServiceBuilder;\n readiness(timing: Timing): ServiceBuilder;\n liveness(timing: Timing): ServiceBuilder;\n startup(budget: Quantity): ServiceBuilder;\n couple(coupling: Coupling): ServiceBuilder;\n phase(name: string, cap: Quantity): ServiceBuilder;\n cooperativeWindow(window: Extent): ServiceBuilder;\n /** This method declares the earliest time of the cooperative abort: half the cap of the drain, or no floor. */\n cooperativeFloor(floor: CooperativeFloor): ServiceBuilder;\n /** This method declares what an exit signal does while the shutdown runs: nothing, or an exit at once. */\n onRepeatSignal(policy: RepeatSignal): ServiceBuilder;\n /** This method declares process triggers that start the shutdown, in addition to the exit signals. */\n trigger(...triggers: ProcessTrigger[]): ServiceBuilder;\n /**\n * This method declares a message of the IPC channel that starts the shutdown, as data. With `as`,\n * the message is that exit signal: `svc.trigger(\"ipc-message\", { match: \"shutdown\", as: \"SIGTERM\" })`.\n */\n trigger(trigger: \"ipc-message\", message: MessageTrigger): ServiceBuilder;\n /** This method declares the exit code of a clean shutdown that a trigger starts, in place of 0. */\n exitCode(trigger: ExitTrigger, code: number): ServiceBuilder;\n /** This method declares each field of a profile, as the method of that field does. */\n profile(profile: Profile): ServiceBuilder;\n /** This method gives the service as data, and it starts nothing. */\n describe(): ServiceDescription;\n /**\n * This method closes the composition, starts the health runtime, and gives it after one warm-up\n * sweep of each check. A part that joins after it starts tripped, and it makes the export\n * partial. A second use gives the same runtime.\n */\n start(options?: StartOptions): Promise<Health>;\n /**\n * This method starts the whole lifecycle and gives it when its startup ends: the service operates,\n * or its startup failed and it shuts down. It refuses a declaration that it cannot start: a transport\n * without its implementation, or a stage with work and no declared phase.\n */\n run(options?: RunOptions): Promise<Lifecycle>;\n /**\n * This value is the health runtime from the time that `start()` begins, or null before. Thus the\n * probes can answer during the warm-up sweep: the startup probe fails until the sweep ends.\n */\n readonly health: Health | null;\n /**\n * This value is the lifecycle from the time that `run()` begins, or null before. Its request\n * tracking operates while the transports start, before `run()` gives it.\n */\n readonly lifecycle: Lifecycle | null;\n}\n\nconst isTime = (amount: Extent): boolean => convertible(amount.unit, \"s\");\nconst above = (amount: Extent): boolean =>\n amount.value === \"infinite\" || (isTime(amount) && valueIn(amount as Quantity, \"s\") > 0);\nconst whole = (count: number): boolean => Number.isInteger(count) && count >= 1;\n\n/** This function gives the problems of a timing: a zero interval or count fails decoding. */\nconst timingProblems = (policy: Gate, timing: Timing): string[] => {\n if (timing.type === \"debounce\") {\n const problems: string[] = [];\n if (!above(timing.interval)) problems.push(`the ${policy} debounce polls at an interval that is not above zero`);\n if (!whole(timing.failAfter)) problems.push(`the ${policy} debounce fails after ${timing.failAfter} polls, not a whole number above zero`);\n if (!whole(timing.recoverAfter)) problems.push(`the ${policy} debounce recovers after ${timing.recoverAfter} polls, not a whole number above zero`);\n return problems;\n }\n const negative = (amount: Quantity | undefined): boolean =>\n amount !== undefined && (!isTime(amount) || valueIn(amount, \"s\") < 0);\n return negative(timing.failAfter) || negative(timing.recoverAfter)\n ? [`the ${policy} window is not a time of zero or more`]\n : [];\n};\n\n/** This function gives the problems of the rules of the shutdown: an unknown name, or an exit code that a process cannot give. */\nconst shutdownProblems = (\n floor: CooperativeFloor | undefined,\n repeat: RepeatSignal | undefined,\n triggers: readonly ProcessTrigger[],\n exitCodes: ExitCodes,\n messages: readonly MessageTrigger[],\n): string[] => {\n const problems: string[] = [];\n if (floor !== undefined && floor !== \"half\" && floor !== \"none\")\n problems.push(`the cooperative floor ${String(floor)} is not \"half\" or \"none\"`);\n if (repeat !== undefined && repeat !== \"ignore\" && repeat !== \"exit\")\n problems.push(`the policy of a repeat signal ${String(repeat)} is not \"ignore\" or \"exit\"`);\n for (const trigger of triggers)\n if (!PROCESS_TRIGGERS.includes(trigger))\n problems.push(`the trigger ${String(trigger)} is not a process trigger (${PROCESS_TRIGGERS.join(\", \")})`);\n if (triggers.includes(\"ipc-message\") && messages.length === 0)\n problems.push(`the trigger ipc-message has no message to match: declare it with svc.trigger(\"ipc-message\", { match })`);\n for (const message of messages) {\n if (!isMessageShape(message.match))\n problems.push(`the match of a message trigger is not a value of JSON: ${String(message.match)}`);\n if (message.as !== undefined && !isExitSignal(message.as))\n problems.push(`a message trigger stands for ${String(message.as)}, not an exit signal (${EXIT_SIGNALS.join(\", \")})`);\n }\n for (const [trigger, code] of Object.entries(exitCodes)) {\n const known = (EXIT_SIGNALS as readonly string[]).includes(trigger) || triggers.includes(trigger as ProcessTrigger);\n if (!known) problems.push(`the exit code of ${trigger} names no exit signal and no declared trigger`);\n if (code === undefined || !isExitCode(code))\n problems.push(`the exit code of ${trigger} is ${String(code)}, not a whole number from 0 to 255`);\n }\n return problems;\n};\n\n/** This function starts the composition of a service. */\nexport const service = (name: string): ServiceBuilder => {\n if (name.trim().length === 0) throw new Error(\"a service needs a name\");\n const transports: Transport[] = [];\n const dependencies: Dependency[] = [];\n const controllers: Array<{\n name: string;\n requires: string[];\n routes: Record<string, Operation>;\n patterns: RoutePattern[];\n }> = [];\n // the function of each route pattern, by controller and by pattern\n const choices = new Map<string, Map<string, OperationOf>>();\n const checks: Check[] = [];\n const runs = new Map<string, CheckFn>();\n const couplings: Coupling[] = [];\n const phases: Phase[] = [];\n let readiness: Timing | undefined;\n let liveness: Timing | undefined;\n let startup: Quantity | undefined;\n let cooperative: Extent | undefined;\n let floor: CooperativeFloor | undefined;\n let repeat: RepeatSignal | undefined;\n const triggers: ProcessTrigger[] = [];\n const messages: MessageTrigger[] = [];\n const exitCodes: Partial<Record<ExitTrigger, number>> = {};\n let started = false;\n let partial = false;\n let runtime: Promise<Health> | undefined;\n let live: Runtime | undefined;\n let running: Promise<Lifecycle> | undefined;\n let life: Lifecycle | undefined;\n const transportImpls = new Map<string, TransportImpl>();\n const handles = new Map<string, DependencyHandle>();\n const phaseWork = new Map<string, PhaseWork[]>();\n const watchdogs: WatchdogSpec[] = [];\n let probes: HealthServer | null = null;\n\n /** This function stops a change to the shape of the service after the start. */\n const composing = (what: string): void => {\n if (started) throw new Error(`${name} has started: ${what} is declared before svc.start()`);\n };\n const once = (list: ReadonlyArray<{ name: string }>, entry: string, what: string): void => {\n if (list.some((held) => held.name === entry))\n throw new Error(`${name} already has a ${what} named ${entry}`);\n };\n const transport =\n (kind: Transport[\"kind\"]) =>\n (entry: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl) => {\n composing(`a ${kind}`);\n once(transports, entry, \"transport\");\n transports.push({ name: entry, kind, knobs: { ...knobs } });\n if (impl !== undefined) transportImpls.set(entry, impl);\n return builder;\n };\n\n /** This function makes the runtime of the declaration: its checks, and a watchdog for each spec. */\n const makeRuntime = (\n options: StartOptions,\n ): { runtime: Runtime; description: ServiceDescription; stopPollers: () => void } => {\n const description = builder.describe();\n const clock = options.clock ?? realClock;\n const dogs: Watchdog[] = [];\n const all = new Map(runs);\n for (const spec of watchdogs) {\n const dog = watchdog(clock, spec, (from, to, on) =>\n options.record?.({ at: clock.now(), machine: \"watchdog\", instance: spec.name, from, to, on }),\n );\n dogs.push(dog);\n all.set(spec.name, () => dog.check());\n }\n const stopPollers = (): void => {\n for (const dog of dogs) dog.stop();\n };\n let made: Runtime;\n try {\n made = healthRuntime(description, all, options);\n } catch (error) {\n stopPollers();\n throw error;\n }\n // the stop of the health runtime also stops the watchdogs\n const runtime: Runtime = {\n ...made,\n stop: () => {\n made.stop();\n stopPollers();\n },\n };\n return { runtime, description, stopPollers };\n };\n\n const builder: ServiceBuilder = {\n name,\n get health() {\n return live ?? null;\n },\n get lifecycle() {\n return life ?? null;\n },\n dependency(entry, spec, handle) {\n once(dependencies, entry, \"dependency\");\n // a dependency that joins after the start has no connection that the lifecycle opens\n if (handle !== undefined && !started) handles.set(entry, handle);\n dependencies.push({\n name: entry,\n ...spec,\n knobs: { ...spec.knobs },\n operations: { ...spec.operations },\n });\n if (started) {\n partial = true;\n live?.addDependency(entry);\n }\n return builder;\n },\n server: transport(\"server\"),\n consumer: transport(\"consumer\"),\n worker: transport(\"worker\"),\n controller(entry) {\n composing(\"a controller\");\n once(controllers, entry, \"controller\");\n const held = {\n name: entry,\n requires: [] as string[],\n routes: {} as Record<string, Operation>,\n patterns: [] as RoutePattern[],\n };\n controllers.push(held);\n const handle: ControllerBuilder = {\n requires(...needed) {\n composing(`what ${entry} requires`);\n held.requires.push(...needed);\n return handle;\n },\n route(served, operation) {\n composing(`${entry}'s routes`);\n if (held.routes[served] !== undefined)\n throw new Error(`${entry} already serves ${served}`);\n held.routes[served] = { ...operation };\n return handle;\n },\n pattern(pattern, operations, operationOf) {\n composing(`${entry}'s route patterns`);\n if (held.patterns.some((each) => each.pattern === pattern))\n throw new Error(`${entry} already has the route pattern ${pattern}`);\n // the function is not data, thus the builder checks it here, and describe() checks the rest\n if (operationOf === undefined && Object.keys(operations).length > 1)\n throw new Error(`${entry}'s pattern ${pattern} has ${Object.keys(operations).length} operations, thus it needs the function that picks one`);\n held.patterns.push({\n pattern,\n operations: Object.fromEntries(Object.entries(operations).map(([name, operation]) => [name, { ...operation }])),\n });\n if (operationOf !== undefined) {\n const mine = choices.get(entry) ?? new Map<string, OperationOf>();\n mine.set(pattern, operationOf);\n choices.set(entry, mine);\n }\n return handle;\n },\n };\n return handle;\n },\n check(check, run) {\n once(checks, check.name, \"check\");\n if (started && run === undefined)\n throw new Error(`check ${check.name} joins after the start, thus it needs its function`);\n checks.push({ ...check });\n if (run !== undefined) runs.set(check.name, run);\n if (started) {\n partial = true;\n live?.addCheck({ ...check, poll: { ...check.poll } }, run!);\n }\n return builder;\n },\n healthServer(server) {\n composing(\"the health server\");\n if (probes !== null) throw new Error(`${name} already has a health server`);\n probes = server;\n return builder;\n },\n onPhase(phase, work) {\n composing(`work for the phase ${phase}`);\n phaseWork.set(phase, [...(phaseWork.get(phase) ?? []), work]);\n return builder;\n },\n watchdog(spec) {\n composing(`the watchdog ${spec.name}`);\n once(checks, spec.name, \"check\");\n // the watchdog is a check on the state of the process itself, on its own connection\n checks.push({\n name: spec.name,\n dependency: null,\n step: \"local-state\",\n ownConnection: true,\n gates: spec.gates,\n poll: { ...spec.poll },\n });\n watchdogs.push(spec);\n return builder;\n },\n readiness(timing) {\n composing(\"readiness\");\n readiness = timing;\n return builder;\n },\n liveness(timing) {\n composing(\"liveness\");\n liveness = timing;\n return builder;\n },\n startup(budget) {\n composing(\"the startup budget\");\n startup = budget;\n return builder;\n },\n couple(coupling) {\n composing(\"a coupling\");\n couplings.push({ ...coupling });\n return builder;\n },\n phase(entry, cap) {\n composing(\"a shutdown phase\");\n once(phases, entry, \"shutdown phase\");\n phases.push({ name: entry, cap });\n return builder;\n },\n cooperativeWindow(window) {\n composing(\"the cooperative window\");\n cooperative = window;\n return builder;\n },\n cooperativeFloor(given) {\n composing(\"the cooperative floor\");\n floor = given;\n return builder;\n },\n onRepeatSignal(policy) {\n composing(\"the policy of a repeat signal\");\n repeat = policy;\n return builder;\n },\n trigger(...given: ReadonlyArray<ProcessTrigger | MessageTrigger>) {\n composing(\"a trigger\");\n const [first, message] = given;\n if (first === \"ipc-message\" && typeof message === \"object\" && message !== null) {\n if (!triggers.includes(\"ipc-message\")) triggers.push(\"ipc-message\");\n messages.push({ ...message });\n return builder;\n }\n for (const each of given) if (typeof each === \"string\" && !triggers.includes(each)) triggers.push(each);\n return builder;\n },\n exitCode(trigger, code) {\n composing(`the exit code of ${trigger}`);\n exitCodes[trigger] = code;\n return builder;\n },\n profile(given) {\n composing(\"a profile\");\n if (given.readiness !== undefined) builder.readiness(given.readiness);\n if (given.liveness !== undefined) builder.liveness(given.liveness);\n if (given.startup !== undefined) builder.startup(given.startup);\n for (const coupling of given.couplings ?? []) builder.couple(coupling);\n for (const each of given.phases ?? []) builder.phase(each.name, each.cap);\n if (given.cooperativeWindow !== undefined) builder.cooperativeWindow(given.cooperativeWindow);\n if (given.cooperativeFloor !== undefined) builder.cooperativeFloor(given.cooperativeFloor);\n if (given.onRepeatSignal !== undefined) builder.onRepeatSignal(given.onRepeatSignal);\n if (given.triggers !== undefined) builder.trigger(...given.triggers);\n for (const message of given.messages ?? []) builder.trigger(\"ipc-message\", message);\n for (const [trigger, code] of Object.entries(given.exitCodes ?? {}))\n if (code !== undefined) builder.exitCode(trigger as ExitTrigger, code);\n return builder;\n },\n describe() {\n const missing: string[] = [];\n if (readiness === undefined) missing.push(\"readiness (svc.readiness)\");\n if (liveness === undefined) missing.push(\"liveness (svc.liveness)\");\n if (startup === undefined) missing.push(\"a startup budget (svc.startup)\");\n if (phases.length === 0) missing.push(\"its shutdown phases (svc.phase)\");\n if (cooperative === undefined)\n missing.push(\"a cooperative window, or no bound (svc.cooperativeWindow)\");\n if (repeat === undefined)\n missing.push(`what a repeat signal does, \"ignore\" or \"exit\" (svc.onRepeatSignal)`);\n if (missing.length > 0)\n throw new Error(\n `${name} does not declare ${missing.join(\"; \")}: the runtime has no defaults`,\n );\n const known = new Set(dependencies.map((entry) => entry.name));\n const problems: string[] = [];\n const policies: Record<Gate, Timing> = { readiness: readiness!, liveness: liveness! };\n for (const gate of [\"readiness\", \"liveness\"] as const)\n problems.push(...timingProblems(gate, policies[gate]));\n for (const check of checks) {\n if (check.dependency !== null && !known.has(check.dependency)) {\n problems.push(\n `check ${check.name} exercises ${check.dependency}, which is not a dependency`,\n );\n }\n if (!isTime(check.poll.interval) || !isTime(check.poll.timeout)) {\n problems.push(`check ${check.name} polls in a unit that is not a time`);\n } else if (!above(check.poll.interval) || !above(check.poll.timeout)) {\n problems.push(`check ${check.name} polls with an interval or a timeout that is not above zero`);\n }\n if (!(check.poll.jitter >= 0 && check.poll.jitter < 1))\n problems.push(`check ${check.name} has a jitter of ${check.poll.jitter}, not a fraction below 1`);\n // a debounce counts the polls of each check that it gates, thus they poll at its interval\n const timing = check.gates === null ? null : policies[check.gates];\n if (\n timing?.type === \"debounce\" &&\n isTime(check.poll.interval) &&\n above(timing.interval) &&\n valueIn(check.poll.interval, \"s\") !== valueIn(timing.interval, \"s\")\n )\n problems.push(\n `check ${check.name} polls every ${valueIn(check.poll.interval, \"s\")} s, but the ${check.gates} debounce counts polls every ${valueIn(timing.interval, \"s\")} s`,\n );\n }\n for (const controller of controllers) {\n for (const needed of controller.requires) {\n if (!known.has(needed))\n problems.push(\n `controller ${controller.name} requires ${needed}, which is not a dependency`,\n );\n }\n for (const [route, operation] of Object.entries(controller.routes))\n problems.push(...operationProblems(`controller ${controller.name}`, route, operation));\n for (const declared of controller.patterns)\n problems.push(...routePatternProblems(`controller ${controller.name}`, declared));\n }\n for (const dependency of dependencies)\n for (const [name, operation] of Object.entries(dependency.operations))\n problems.push(...operationProblems(`dependency ${dependency.name}`, name, operation));\n for (const phase of phases)\n if (!isTime(phase.cap)) problems.push(`phase ${phase.name}'s cap is not a time`);\n problems.push(...shutdownProblems(floor, repeat, triggers, exitCodes, messages));\n // the stages of the shutdown keep their sequence: readiness fails first, the health server closes last\n const ranked = phases.map((phase) => phase.name).filter((each) => stageRank(each) >= 0);\n for (let at = 1; at < ranked.length; at += 1)\n if (stageRank(ranked[at]!) < stageRank(ranked[at - 1]!))\n problems.push(\n `the phase \"${ranked[at]!}\" comes after \"${ranked[at - 1]!}\", but the stages go ${STAGES.join(\", \")}`,\n );\n if (problems.length > 0) throw new Error(`${name}: ${problems.join(\"; \")}`);\n const controllersOut: Controller[] = controllers.map((entry) => ({\n name: entry.name,\n requires: [...entry.requires],\n routes: { ...entry.routes },\n ...(entry.patterns.length === 0\n ? {}\n : { patterns: entry.patterns.map((each) => ({ pattern: each.pattern, operations: { ...each.operations } })) }),\n }));\n return {\n format: FORMAT,\n name,\n partial,\n transports: transports.map((entry) => ({ ...entry, knobs: { ...entry.knobs } })),\n dependencies: dependencies.map((entry) => ({\n ...entry,\n knobs: { ...entry.knobs },\n operations: { ...entry.operations },\n })),\n controllers: controllersOut,\n checks: checks.map((entry) => ({ ...entry, poll: { ...entry.poll } })),\n policies: { readiness: readiness!, liveness: liveness!, startup: startup! },\n couplings: couplings.map((entry) => ({ ...entry })),\n shutdown: {\n phases: phases.map((entry) => ({ ...entry })),\n cooperativeWindow: cooperative!,\n ...(floor === undefined ? {} : { cooperativeFloor: floor }),\n onRepeatSignal: repeat!,\n ...(triggers.length === 0 ? {} : { triggers: [...triggers] }),\n ...(messages.length === 0 ? {} : { messages: messages.map((each) => ({ ...each })) }),\n ...(Object.keys(exitCodes).length === 0 ? {} : { exitCodes: { ...exitCodes } }),\n },\n };\n },\n start(options = {}) {\n // the start needs the whole graph: describe() is the check, and the runtime reads it\n if (runtime !== undefined) return runtime;\n if (running !== undefined) return Promise.reject(new Error(`${name} runs its lifecycle: use its health`));\n let made: Runtime;\n try {\n made = makeRuntime(options).runtime;\n } catch (error) {\n return Promise.reject(error);\n }\n started = true;\n live = made;\n runtime = made.warmUp().then(() => made);\n return runtime;\n },\n run(options = {}) {\n if (running !== undefined) return running;\n if (runtime !== undefined) return Promise.reject(new Error(`${name} started its health only: run() starts the whole lifecycle`));\n try {\n const description = builder.describe();\n const components: Components = {\n transports: transportImpls,\n dependencies: handles,\n healthServer: probes,\n phaseWork,\n choices,\n stopPollers: () => {},\n };\n const problems = lifecycleProblems(description, components);\n if (problems.length > 0) throw new Error(`${name}: ${problems.join(\"; \")}`);\n const made = makeRuntime(options);\n started = true;\n live = made.runtime;\n // the builder holds the lifecycle before the first transport starts\n const ran = lifecycle(made.description, made.runtime, { ...components, stopPollers: made.stopPollers }, options, (given) => {\n life = given;\n });\n running = ran.started.then(() => ran);\n } catch (error) {\n return Promise.reject(error);\n }\n return running;\n },\n };\n return builder;\n};\n","/**\n * This module is the evaluator of the timer-ordering law. Its decisions are the same as the\n * decisions of the research evaluator. The rules are data, and the caller gives them. Each rule\n * is one or more linear inequalities over symbols at a hop (`readiness_detection_window@pod`),\n * with a margin. A binding maps `symbol@hop` to seconds, or to \"inf\" for a timer that is absent.\n */\n\n/** A term is a coefficient times one symbol, at a hop when it has one. */\nexport interface Term {\n readonly knob: string;\n readonly coef: number;\n readonly at?: string | undefined;\n}\n\n/** A side is a sum of terms, plus a constant. */\nexport interface Side {\n readonly terms: readonly Term[];\n readonly const?: number | undefined;\n}\n\n/** An inequality compares two sides, with a margin. */\nexport interface Inequality {\n readonly lhs: Side;\n readonly op: \"<\" | \"<=\" | \">\" | \">=\";\n readonly rhs: Side;\n /** The margin is in seconds, or it is words for a margin that no binding gives (\"a factor of several\"). Words count as 0. */\n readonly margin?: number | string | undefined;\n}\n\n/** A rule is one or more inequalities, with their statement in words. */\nexport interface Rule {\n readonly id: string;\n /** This text is the rule in words. */\n readonly rule: string;\n /** This text is the window that a violation opens. */\n readonly window?: string | undefined;\n readonly expr: Inequality;\n readonly expr_more?: readonly Inequality[] | undefined;\n}\n\n/** A bound is in seconds, or it is \"inf\" for an absent timer, or \"off\" for a disabled feature. The last two have no limit. */\nexport type Bound = number | \"inf\" | \"off\";\n\n/**\n * A binding maps `symbol@hop` to its bound. Its \"margin\" replaces the margin of each inequality.\n * Its \"margins\" replace them one by one, in sequence, as the binding of a chain can.\n */\nexport type Binding = Readonly<Record<string, Bound | readonly number[] | undefined>> & {\n readonly margin?: number | undefined;\n readonly margins?: readonly number[] | undefined;\n};\n\n/** A verdict is \"holds\", \"violated\", \"unbounded\" (it holds only because a timer is absent) or \"depends\" (nothing is bound). */\nexport type Verdict = \"holds\" | \"violated\" | \"unbounded\" | \"depends\";\n\n/** An evaluation is the value of each side of one inequality, its margin, and if it holds. */\nexport interface Evaluated {\n readonly lhs: number | null;\n readonly rhs: number | null;\n readonly margin: number;\n readonly holds: boolean | null;\n}\n\nconst value = (bound: Bound): number =>\n bound === \"inf\" || bound === \"off\" ? Infinity : Number(bound);\nconst keyOf = (term: Term): string =>\n term.at !== undefined ? `${term.knob}@${term.at}` : term.knob;\n/** This function gives the bound of a symbol, or undefined when the symbol has no bound. */\nconst boundOf = (bind: Binding, key: string): Bound | undefined => {\n const bound = bind[key];\n return typeof bound === \"number\" || bound === \"inf\" || bound === \"off\" ? bound : undefined;\n};\n\n/** This function gives the inequalities of a rule: its expr, then the others. */\nexport const inequalities = (rule: Rule): readonly Inequality[] => [\n rule.expr,\n ...(rule.expr_more ?? []),\n];\n\n/** This function gives the symbols that a rule reads, as `symbol@hop`. */\nexport const symbolsOf = (rule: Rule): string[] => {\n const out: string[] = [];\n for (const inequality of inequalities(rule)) {\n for (const term of [...inequality.lhs.terms, ...inequality.rhs.terms]) {\n const key = keyOf(term);\n if (!out.includes(key)) out.push(key);\n }\n }\n return out;\n};\n\n/** This function gives the value of a side, Σ coef × symbol + const, or null when a symbol has no bound. */\nconst sideOf = (side: Side, bind: Binding): number | null => {\n let total = side.const ?? 0;\n for (const term of side.terms) {\n const bound = boundOf(bind, keyOf(term));\n if (bound === undefined) return null;\n total += term.coef * value(bound);\n }\n return total;\n};\n\n/** This function gives the margin of an inequality: from the binding (one for all, or one each), else from the rule, else 0. */\nconst marginOf = (inequality: Inequality, index: number, bind: Binding): number => {\n if (Array.isArray(bind.margins)) return Number(bind.margins[index] ?? 0);\n if (typeof bind.margin === \"number\") return bind.margin;\n return typeof inequality.margin === \"number\" ? inequality.margin : 0;\n};\n\n/**\n * This function evaluates each inequality on one binding. \"<\" holds when lhs + margin < rhs, and\n * \">\" holds when lhs > rhs + margin. Only the inequalities with all their symbols bound apply.\n * The others are null.\n */\nexport const evaluate = (rule: Rule, bind: Binding): Evaluated[] =>\n inequalities(rule).map((inequality, index) => {\n const lhs = sideOf(inequality.lhs, bind);\n const rhs = sideOf(inequality.rhs, bind);\n const margin = marginOf(inequality, index, bind);\n if (lhs === null || rhs === null) return { lhs, rhs, margin, holds: null };\n const holds =\n inequality.op === \"<\"\n ? lhs + margin < rhs\n : inequality.op === \"<=\"\n ? lhs + margin <= rhs\n : inequality.op === \">\"\n ? lhs > rhs + margin\n : lhs >= rhs + margin;\n return { lhs, rhs, margin, holds };\n });\n\n/**\n * This function gives the verdict of an evaluation. When an applicable inequality fails, the\n * verdict is \"violated\". When all hold only because a timer is absent, the verdict is \"unbounded\",\n * because nothing then limits the window. Otherwise the verdict is \"holds\". When no inequality\n * applies, the arithmetic cannot decide, and the verdict is \"depends\".\n */\nexport const verdictOf = (rule: Rule, bind: Binding, evaluated: readonly Evaluated[]): Verdict => {\n const applicable = evaluated.flatMap((entry, index) => (entry.holds === null ? [] : [index]));\n if (applicable.length === 0) return \"depends\";\n if (applicable.some((index) => evaluated[index]?.holds === false)) return \"violated\";\n const all = inequalities(rule);\n const infinite = applicable.some((index) => {\n const inequality = all[index]!;\n return [...inequality.lhs.terms, ...inequality.rhs.terms].some((term) => {\n const bound = boundOf(bind, keyOf(term));\n return bound !== undefined && value(bound) === Infinity;\n });\n });\n return infinite ? \"unbounded\" : \"holds\";\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { convertExact, convertible, rationals as r } from \"@mark1russell7/quantity\";\nimport type { Dependency, ServiceDescription, Transport } from \"./description.ts\";\nimport type { Binding, Bound, Evaluated, Rule, Verdict } from \"./law.ts\";\nimport { evaluate, symbolsOf, verdictOf } from \"./law.ts\";\nimport { failSpan } from \"./timing.ts\";\n\n/**\n * This module applies the ordering law to a declaration. The declaration binds the symbols of the\n * service, from its primitives: the polls of its checks, the windows of its policies, its drain.\n * The scenario binds the symbols of the platform (preStop, grace, the probes of the kubelet,\n * propagation) and of each dependency (its failover time, the idle close of its server). Thus the\n * service gives the inequalities, and the scenario gives the values. A rule about a client\n * applies one time for each dependency. A rule about a consumer applies one time for each consumer\n * and each worker.\n */\n\n/** A scenario gives the values of the platform and of each dependency, by the `symbol@hop` of the law. */\nexport interface Scenario {\n /** These are the values of the platform: prestop_sleep@pod, termination_grace@pod, probe_period@pod, propagation_bound@cluster. */\n readonly platform: Readonly<Record<string, Extent>>;\n /**\n * These are the probe windows of the kubelet, period × failure threshold. They add to the\n * windows of the declaration. A probe reads the cached verdict, thus detection is the latch,\n * then the probe.\n */\n readonly probes: { readonly readiness: Quantity; readonly liveness: Quantity };\n /** These are the values of each dependency, by its name: failover_time@dependency, server_idle_close@server. */\n readonly dependencies?: Readonly<Record<string, Readonly<Record<string, Extent>>>> | undefined;\n /** These are the values of the source of each consumer and worker, by its name and by the `symbol@hop` of the law: lease_duration@broker. */\n readonly transports?: Readonly<Record<string, Readonly<Record<string, Extent>>>> | undefined;\n}\n\n/** A finding is the verdict of one rule for one scope: the service, or the client of a dependency. */\nexport interface Finding {\n readonly rule: string;\n readonly scope: string;\n readonly verdict: Verdict;\n readonly statement: string;\n readonly window?: string | undefined;\n readonly evaluated: readonly Evaluated[];\n /** These are the symbols that have no bound. A \"depends\" verdict waits for them. */\n readonly unbound: readonly string[];\n}\n\n/** These are the identifiers of the rules that each declaration gets. */\nexport const SERVICE_RULES: readonly string[] = [\n \"O04\",\n \"O09\",\n \"O10\",\n \"O11\",\n \"O12\",\n \"O13\",\n \"O14\",\n \"O15\",\n \"O16\",\n \"O17\",\n \"O18\",\n \"O19\",\n \"O20\",\n \"O21\",\n \"O22\",\n \"O23\",\n \"O27\",\n];\n\n/** This function gives a finite amount in seconds. */\nconst secondsOf = (amount: Quantity): number =>\n r.toNumber(convertExact(r.fromNumber(amount.value), amount.unit, \"s\"));\n/** This function gives an amount, or no bound, as the law binds it. */\nconst boundOf = (amount: Extent): Bound =>\n amount.value === \"infinite\" ? \"inf\" : secondsOf(amount);\n/** This function tells if a unit is a time. A unit that the package does not know is not a time. */\nconst isTime = (unit: string): boolean => {\n try {\n return convertible(unit, \"s\");\n } catch {\n return false;\n }\n};\n/** This function gives the largest of some numbers of seconds, or undefined when there are none. */\nconst most = (values: readonly number[]): number | undefined =>\n values.length === 0 ? undefined : Math.max(...values);\n\n/** This function gives what the declaration tells about the service, as symbols of the law, and the source of each. */\nexport const serviceBindings = (\n svc: ServiceDescription,\n scenario: Scenario,\n): { readonly bind: Record<string, Bound>; readonly from: Record<string, string> } => {\n const bind: Record<string, Bound> = {};\n const from: Record<string, string> = {};\n const set = (symbol: string, bound: Bound | undefined, said: string): void => {\n if (bound === undefined) return;\n bind[symbol] = bound;\n from[symbol] = said;\n };\n const gating = svc.checks.filter((check) => check.gates !== null);\n const readinessChecks = gating.filter((check) => check.gates === \"readiness\");\n const livenessChecks = gating.filter((check) => check.gates === \"liveness\");\n set(\n \"check_poll_interval@service\",\n most(gating.map((check) => secondsOf(check.poll.interval))),\n \"the slowest gating check's interval\",\n );\n set(\n \"check_timeout@service\",\n most(gating.map((check) => secondsOf(check.poll.timeout))),\n \"the longest gating check's timeout\",\n );\n set(\n \"slowest_poll@service\",\n most(\n gating.map(\n (check) =>\n secondsOf(check.poll.timeout) + secondsOf(check.poll.interval) * (1 + check.poll.jitter),\n ),\n ),\n \"a check's timeout plus one jittered interval, at its slowest\",\n );\n // the window of a policy is the time that its latch takes to fail when its slowest check times out\n const windowOf = (checks: typeof gating, policy: \"readiness\" | \"liveness\"): number | undefined =>\n most(\n checks.map((check) => secondsOf(failSpan(svc.policies[policy], check.poll, \"timeout\").max)),\n );\n const readiness = windowOf(readinessChecks, \"readiness\");\n const liveness = windowOf(livenessChecks, \"liveness\");\n set(\"readiness_detection_window@service\", readiness, \"the readiness latch, failing by timeout\");\n if (readiness !== undefined) {\n set(\n \"readiness_detection_window@pod\",\n readiness + secondsOf(scenario.probes.readiness),\n \"the readiness latch, then the kubelet's probe\",\n );\n }\n if (liveness !== undefined) {\n set(\n \"liveness_detection_window@pod\",\n liveness + secondsOf(scenario.probes.liveness),\n \"the liveness window, then the kubelet's probe\",\n );\n }\n set(\"startup_budget@pod\", secondsOf(svc.policies.startup), \"the declared startup budget\");\n set(\n \"process_drain_time@process\",\n svc.shutdown.phases.reduce((total, phase) => total + secondsOf(phase.cap), 0),\n `the shutdown phases' caps, summed (${svc.shutdown.phases.map((phase) => phase.name).join(\", \")})`,\n );\n set(\n \"cooperative_window@process\",\n boundOf(svc.shutdown.cooperativeWindow),\n \"the declared cooperative window\",\n );\n // the hold of \"fail readiness\" keeps the listener open after the signal, as a preStop sleep does\n const hold = svc.shutdown.phases.find((phase) => phase.name === \"fail readiness\");\n set(\n \"readiness_hold@process\",\n hold === undefined ? 0 : secondsOf(hold.cap),\n hold === undefined\n ? \"no fail readiness phase: the intake stops at once after the signal\"\n : \"the cap of the fail readiness phase, which holds while the endpoints update\",\n );\n for (const [symbol, amount] of Object.entries(scenario.platform))\n set(symbol, boundOf(amount), \"the scenario\");\n return { bind, from };\n};\n\n/** This function gives the client knobs of a dependency at @client, and the values of the scenario at its own hops. */\nconst dependencyBindings = (dependency: Dependency, scenario: Scenario): Record<string, Bound> => {\n const bind: Record<string, Bound> = {};\n for (const [knob, amount] of Object.entries(dependency.knobs))\n bind[`${knob}@client`] = boundOf(amount);\n for (const [symbol, amount] of Object.entries(scenario.dependencies?.[dependency.name] ?? {})) {\n bind[symbol.includes(\"@\") ? symbol : `${symbol}@dependency`] = boundOf(amount);\n }\n return bind;\n};\n\n/**\n * These are the hops of the law at which the knobs of a transport bind, by its kind. A worker does\n * its units as a consumer does, thus both bind at `consumer` (O20). A server binds at no hop yet.\n */\nconst TRANSPORT_HOPS: Readonly<Record<Transport[\"kind\"], string | null>> = { server: null, consumer: \"consumer\", worker: \"consumer\" };\n\n/**\n * This function gives the time knobs of a transport at the hop of its kind, and the values of the\n * scenario for its source. A knob with a hop in its name binds at that hop. A count binds no symbol.\n */\nconst transportBindings = (transport: Transport, hop: string, scenario: Scenario): Record<string, Bound> => {\n const bind: Record<string, Bound> = {};\n for (const [knob, amount] of Object.entries(transport.knobs)) {\n if (!isTime(amount.unit)) continue;\n bind[knob.includes(\"@\") ? knob : `${knob}@${hop}`] = boundOf(amount);\n }\n for (const [symbol, amount] of Object.entries(scenario.transports?.[transport.name] ?? {})) bind[symbol] = boundOf(amount);\n return bind;\n};\n\nconst SCOPED = /@(client|dependency|server)$/;\nconst TRANSPORT_SCOPED = /@consumer$/;\n\n/** This identifier is the rule of the findings about a field that the declaration does not give. */\nexport const DECLARATION_RULE = \"declaration\";\n\n/**\n * This function gives a finding for each field of the shutdown that a description does not give.\n * `describe()` refuses such a declaration. A description from another source, for example the\n * JSON of 0.4, can lack the field. The verdict is `depends`, and `unbound` names the field.\n */\nconst declarationFindings = (svc: ServiceDescription): Finding[] =>\n (svc.shutdown as { onRepeatSignal?: unknown }).onRepeatSignal === undefined\n ? [\n {\n rule: DECLARATION_RULE,\n scope: svc.name,\n verdict: \"depends\",\n statement: \"the declaration tells what a signal does while the shutdown runs: ignore or exit\",\n window: \"a repeat signal has no declared effect\",\n evaluated: [],\n unbound: [\"shutdown.onRepeatSignal\"],\n },\n ]\n : [];\n\n/**\n * This function applies each service rule to a declaration and a scenario. A rule applies one time\n * for the service, for each client, or for each consumer and worker. The function also gives a\n * finding for each necessary field that the description does not give (`DECLARATION_RULE`).\n */\nexport const lint = (\n svc: ServiceDescription,\n scenario: Scenario,\n rules: readonly Rule[],\n): Finding[] => {\n const service = serviceBindings(svc, scenario).bind;\n const findings: Finding[] = [...declarationFindings(svc)];\n for (const rule of rules) {\n if (!SERVICE_RULES.includes(rule.id)) continue;\n const symbols = symbolsOf(rule);\n const scopes: Array<[string, Binding]> = symbols.some((symbol) => TRANSPORT_SCOPED.test(symbol))\n ? svc.transports.flatMap((transport): Array<[string, Binding]> => {\n const hop = TRANSPORT_HOPS[transport.kind];\n return hop === null ? [] : [[transport.name, { ...service, ...transportBindings(transport, hop, scenario) }]];\n })\n : symbols.some((symbol) => SCOPED.test(symbol))\n ? svc.dependencies.map((dependency) => [\n dependency.name,\n { ...service, ...dependencyBindings(dependency, scenario) },\n ])\n : [[svc.name, service]];\n for (const [scope, bind] of scopes) {\n const evaluated = evaluate(rule, bind);\n findings.push({\n rule: rule.id,\n scope,\n verdict: verdictOf(rule, bind, evaluated),\n statement: rule.rule,\n ...(rule.window !== undefined ? { window: rule.window } : {}),\n evaluated,\n unbound: symbols.filter((symbol) => bind[symbol] === undefined),\n });\n }\n }\n return findings;\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { convertible, valueIn } from \"@mark1russell7/quantity\";\nimport type { CooperativeFloor, Coupling, ExitCodes, MessageTrigger, Phase, RepeatSignal } from \"./description.ts\";\nimport type { ProcessTrigger } from \"./process.ts\";\nimport type { Timing } from \"./timing.ts\";\n\n/**\n * A profile is a part of a declaration as data: policies, phases and the rules of the shutdown.\n * `svc.profile(profile)` declares each field, as its method does. The runtime has no defaults, and\n * a profile is not a default, because the caller gives it. The caller can change each field with a\n * spread. `describe()` then shows the values of the profile.\n *\n * svc.profile({ ...kubernetes({ grace: s(60), preStop: s(5) }), onRepeatSignal: \"exit\" });\n */\nexport interface Profile {\n readonly readiness?: Timing | undefined;\n readonly liveness?: Timing | undefined;\n readonly startup?: Quantity | undefined;\n readonly couplings?: readonly Coupling[] | undefined;\n /** These are the phases of the shutdown, in their sequence. */\n readonly phases?: readonly Phase[] | undefined;\n readonly cooperativeWindow?: Extent | undefined;\n readonly cooperativeFloor?: CooperativeFloor | undefined;\n readonly onRepeatSignal?: RepeatSignal | undefined;\n readonly triggers?: readonly ProcessTrigger[] | undefined;\n /** These messages of the IPC channel start the shutdown, as `svc.trigger(\"ipc-message\", message)` declares each one. */\n readonly messages?: readonly MessageTrigger[] | undefined;\n readonly exitCodes?: ExitCodes | undefined;\n}\n\nconst s = (value: number): Quantity => ({ value, unit: \"s\" });\nconst phase = (name: string, cap: Quantity): Phase => ({ name, cap });\n\n/**\n * This profile is for a service on the computer of a developer. No load balancer routes to it,\n * thus it has no readiness hold. Its caps sum to 10 s, and a second signal exits at once. It\n * declares no checks, thus the caller declares readiness, liveness and the startup budget.\n */\nexport const localDev: Profile = {\n phases: [\n phase(\"stop intake\", s(1)),\n phase(\"drain\", s(4)),\n phase(\"close transports\", s(1)),\n phase(\"stop the poller\", s(1)),\n phase(\"tear down dependencies\", s(1)),\n phase(\"close the health server\", s(1)),\n phase(\"flush the output\", s(1)),\n ],\n cooperativeWindow: s(2),\n cooperativeFloor: \"half\",\n onRepeatSignal: \"exit\",\n};\n\n/**\n * This profile is for a background host on the computer of a developer, under a supervisor or a\n * command that stops it. It has the caps of `localDev`. A repeat signal has no effect, thus the\n * host ends its drain. It has no process trigger: a background host has no parent on stdin.\n */\nexport const daemon: Profile = {\n phases: localDev.phases!.map((each) => ({ ...each })),\n cooperativeWindow: localDev.cooperativeWindow!,\n cooperativeFloor: \"half\",\n onRepeatSignal: \"ignore\",\n};\n\n/**\n * This profile is for a small process: a command that runs one time, or a child process on stdio.\n * It has no checks and no probes, and its policies gate nothing. The cooperative abort occurs at the\n * start of the drain, thus a first Ctrl-C stops the work at once. A second signal exits at once.\n * The exit codes tell the shell how the process stopped: 130 for SIGINT, 143 for SIGTERM and 131\n * for SIGQUIT. A stdio child also declares `triggers: [\"stdin-close\"]`.\n */\nexport const ephemeral: Profile = {\n readiness: { type: \"window\", failAfter: s(0) },\n liveness: { type: \"window\", failAfter: s(0) },\n startup: s(10),\n phases: [\n phase(\"stop intake\", s(1)),\n phase(\"drain\", s(2)),\n phase(\"close transports\", s(1)),\n phase(\"stop the poller\", s(1)),\n phase(\"tear down dependencies\", s(2)),\n phase(\"flush the output\", s(1)),\n ],\n // the window is the whole drain, and no floor holds the abort back\n cooperativeWindow: s(2),\n cooperativeFloor: \"none\",\n onRepeatSignal: \"exit\",\n exitCodes: { SIGINT: 130, SIGTERM: 143, SIGQUIT: 131 },\n};\n\n/** These are the parts of the budget of each stage in the profile `kubernetes`, in thirtieths. */\nconst KUBERNETES_SHARES: ReadonlyArray<readonly [string, number]> = [\n [\"fail readiness\", 2],\n [\"stop intake\", 5],\n [\"drain\", 15],\n [\"close transports\", 2],\n [\"stop the poller\", 1],\n [\"tear down dependencies\", 2],\n [\"close the health server\", 1],\n];\n/** This part of the budget is the cooperative window, in thirtieths. */\nconst KUBERNETES_WINDOW = 5;\n\n/** These are the settings of a pod that the profile `kubernetes` derives its caps from. */\nexport interface PodTiming {\n /** This time is `terminationGracePeriodSeconds`: from the deletion of the pod to SIGKILL. */\n readonly grace: Quantity;\n /** This time is the preStop sleep, or 0 for no preStop hook. SIGTERM comes after it. */\n readonly preStop: Quantity;\n}\n\n/**\n * This function gives the profile of a pod in Kubernetes. The budget is the grace less the preStop\n * sleep: the time from SIGTERM to SIGKILL. Each stage gets a part of the budget, rounded down to\n * the millisecond.\n * - The parts in thirtieths are 2, 5, 15, 2, 1, 2 and 1, in the sequence of the stages. Thus 2\n * thirtieths of the budget stay as a margin before SIGKILL.\n * - The cooperative window is 5 thirtieths of the budget.\n * - The kubelet sends SIGTERM one time, thus a repeat signal has no effect.\n *\n * At the defaults of Kubernetes (a grace of 30 s and no preStop hook), the caps are 2, 5, 15, 2, 1,\n * 2 and 1 s. Thus the sum of the caps and the preStop sleep fits in the grace (O10). The window is\n * shorter than the drain, which is shorter than the budget (O16).\n */\nexport const kubernetes = (pod: PodTiming): Profile => {\n const time = (amount: Quantity, what: string): number => {\n if (!convertible(amount.unit, \"s\")) throw new Error(`the ${what} of the pod is not a time`);\n return valueIn(amount, \"ms\");\n };\n const grace = time(pod.grace, \"grace\");\n const preStop = time(pod.preStop, \"preStop sleep\");\n if (preStop < 0) throw new Error(\"the preStop sleep of the pod is less than 0\");\n const budget = grace - preStop;\n if (!(budget > 0)) throw new Error(`the grace of the pod (${grace} ms) is not longer than its preStop sleep (${preStop} ms)`);\n const part = (thirtieths: number): Quantity => s(Math.floor((budget * thirtieths) / 30) / 1000);\n return {\n phases: KUBERNETES_SHARES.map(([name, thirtieths]) => phase(name, part(thirtieths))),\n cooperativeWindow: part(KUBERNETES_WINDOW),\n cooperativeFloor: \"half\",\n onRepeatSignal: \"ignore\",\n };\n};\n","// The units of work of a worker loop and of a queue drain: the count of the units in flight, the\n// drain to a deadline with the cooperative abort, the sleeps on the clock, the bound of each unit,\n// and the request tracking of the service for each unit.\n\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Backoff } from \"./backoff.ts\";\nimport { backoffProblems } from \"./backoff.ts\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport type { KnobRecord } from \"./knobs.ts\";\nimport { boundedMillisecondsOf } from \"./knobs.ts\";\nimport type { Lifecycle } from \"./lifecycle.ts\";\nimport type { RequestEnd } from \"./requests.ts\";\n\n/**\n * A unit request names the route of each unit of work in the request tracking of the service. Then\n * the service admits, counts, drains and cuts each unit as it does each request (`life.request`).\n * The controller declares the route, thus its idempotency tells if a cut unit can go again.\n */\nexport interface UnitRequest<U> {\n /** This name is the controller that declares the route. */\n readonly controller: string;\n /** This name is the route of each unit, or a function that gives it from the unit. A route can match a route pattern. */\n readonly route: string | ((unit: U) => string);\n /** This function gives the detail of a unit, for the function of a route pattern. */\n readonly detail?: ((unit: U) => unknown) | undefined;\n}\n\n/**\n * A unit end tells how one unit of work ended:\n * - `done`: the work gave its value.\n * - `failed`: the work threw for a cause of its own, or after its bound aborted it.\n * - `refused`: the service did not admit the unit, thus the work did not start.\n * - `cut`: the shutdown stopped the unit. It is not a failure. `retryable` tells if the unit can go again.\n */\nexport type UnitEnd =\n | { readonly kind: \"done\"; readonly value: unknown }\n | { readonly kind: \"failed\"; readonly error: unknown }\n | { readonly kind: \"refused\"; readonly cause: string }\n | { readonly kind: \"cut\"; readonly cause: string; readonly retryable: boolean };\n\n/** This function gives the cause of an abort as text. */\nexport const causeOf = (signal: AbortSignal): string =>\n signal.reason instanceof Error ? signal.reason.message : String(signal.reason ?? \"the unit got an abort\");\n\n/** These are the parts of one unit of work. */\nexport interface UnitRun<U> {\n readonly clock: Clock;\n /** This time is the bound of the unit, in milliseconds, or infinity. At it, the signal of the work aborts. */\n readonly bound: number;\n /** This controller is the abort of the transport for the unit: the cooperative abort and the close. */\n readonly abort: AbortController;\n readonly life: Lifecycle;\n readonly request: UnitRequest<U> | undefined;\n readonly unit: U;\n /** This function starts the work, and gives its value or a promise. */\n readonly work: (signal: AbortSignal) => unknown;\n}\n\n/**\n * This function does one unit of work, and gives its end. With a request, the unit goes through\n * `life.request`, thus the service counts it, drains it and can cut it. A throw after the abort of\n * the transport is a cut, not a failure (S6 A10). A throw after the bound is a failure.\n */\nexport const runUnit = async <U>(run: UnitRun<U>): Promise<UnitEnd> => {\n const { clock, bound, abort, life, request, unit, work } = run;\n const timeout = new AbortController();\n const cancel: Cancel = Number.isFinite(bound)\n ? clock.after(bound, () => timeout.abort(new Error(`the unit did not end in its unit_processing_time of ${bound} ms`)))\n : () => {};\n const call = async (tracker?: AbortSignal): Promise<unknown> =>\n work(AbortSignal.any(tracker === undefined ? [abort.signal, timeout.signal] : [abort.signal, timeout.signal, tracker]));\n // the transport cannot read the idempotency of the route, thus a cut of its own does not go again\n const thrown = (error: unknown): UnitEnd => {\n if (abort.signal.aborted) return { kind: \"cut\", cause: causeOf(abort.signal), retryable: false };\n if (timeout.signal.aborted) return { kind: \"failed\", error: timeout.signal.reason };\n return { kind: \"failed\", error };\n };\n try {\n if (request === undefined) {\n try {\n return { kind: \"done\", value: await call() };\n } catch (error) {\n return thrown(error);\n }\n }\n let collected: Promise<{ readonly items: readonly unknown[]; readonly end: RequestEnd }>;\n try {\n const route = typeof request.route === \"string\" ? request.route : request.route(unit);\n const detail = request.detail?.(unit);\n // the value goes in a box: a work that gives an async iterable is one value here, not a stream\n const stream = life.request(request.controller, route, (signal) => call(signal).then((value) => ({ value })), detail === undefined ? {} : { detail });\n collected = stream.collect();\n } catch (error) {\n // an undeclared route, or a lifecycle with no service\n return { kind: \"failed\", error };\n }\n const { items, end } = await collected;\n if (end.kind === \"done\") return { kind: \"done\", value: (items[0] as { readonly value: unknown } | undefined)?.value };\n if (end.kind === \"failed\") return thrown(end.error);\n if (end.kind === \"refused\") return { kind: \"refused\", cause: end.cause };\n return { kind: \"cut\", cause: end.cause, retryable: end.retryable };\n } finally {\n cancel();\n }\n};\n\n/** A flight set counts the units in flight, from their events, and drains them to a deadline. */\nexport interface Flights {\n /** This count is the number of units in flight. */\n readonly size: number;\n /** This method adds a unit, and gives the function that removes it. A unit after the cooperative abort gets the abort at once. */\n add(unit: AbortController): () => void;\n /** This method aborts each unit in flight and each later unit: the cooperative abort, or the close. */\n abort(reason: unknown): void;\n /** This method removes each unit from the count: the close cuts them. */\n clear(): void;\n /** This method waits until no unit is in flight, or until the deadline. The signal is the cooperative abort. It does not throw. */\n drain(deadline: number, signal: AbortSignal): Promise<void>;\n /** This method gives a promise that ends when the count goes down, or at `release()`. */\n less(): Promise<void>;\n /** This method ends each promise of `less()`. */\n release(): void;\n}\n\n/** This function makes a flight set on a clock. */\nexport const flights = (clock: Clock): Flights => {\n const units = new Set<AbortController>();\n const idle = new Set<() => void>();\n const lower = new Set<() => void>();\n let aborted: { readonly reason: unknown } | null = null;\n const settle = (): void => {\n for (const done of [...lower]) done();\n lower.clear();\n if (units.size === 0) for (const done of [...idle]) done();\n };\n const abort = (reason: unknown): void => {\n aborted ??= { reason };\n for (const unit of [...units]) if (!unit.signal.aborted) unit.abort(aborted.reason);\n };\n return {\n get size() {\n return units.size;\n },\n add(unit) {\n units.add(unit);\n if (aborted !== null && !unit.signal.aborted) unit.abort(aborted.reason);\n return () => {\n if (units.delete(unit)) settle();\n };\n },\n abort,\n clear() {\n units.clear();\n settle();\n },\n drain(deadline, signal) {\n const cooperative = (): void => abort(signal.reason);\n if (signal.aborted) cooperative();\n else signal.addEventListener(\"abort\", cooperative, { once: true });\n // nothing in flight, or a deadline that passed: the drain ends at once, with no timer\n if (units.size === 0 || deadline <= clock.now()) {\n signal.removeEventListener(\"abort\", cooperative);\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n let cancel: Cancel = () => {};\n const done = (): void => {\n idle.delete(done);\n cancel();\n signal.removeEventListener(\"abort\", cooperative);\n resolve();\n };\n idle.add(done);\n cancel = clock.after(Math.max(0, deadline - clock.now()), done);\n });\n },\n less() {\n return new Promise<void>((resolve) => lower.add(resolve));\n },\n release() {\n for (const done of [...lower]) done();\n lower.clear();\n },\n };\n};\n\n/**\n * A sleeper gives the waits of a loop on the clock. `wake()` ends each wait that it can end, and\n * `stop()` ends each wait. A wait without a bound uses no timer.\n */\nexport interface Sleeper {\n /** This count goes up at each `wake()`. A loop reads it before a unit, and a wake during the unit then ends the next sleep at once. */\n readonly wakes: number;\n /** This method waits on the clock. A wake after `since` ends it, and with `since` past, it ends at once. */\n sleep(ms: number, since: number): Promise<void>;\n /** This method waits on the clock. A wake does not end it: it is a backoff after a failure. */\n backoff(ms: number): Promise<void>;\n /** This method ends each sleep, and gives the count of sleeps that it ended. */\n wake(): number;\n /** This method ends each wait, the backoffs too. Each later wait then ends at once. */\n stop(): void;\n}\n\n/** This function makes a sleeper on a clock. */\nexport const sleeper = (clock: Clock): Sleeper => {\n let wakes = 0;\n let stopped = false;\n const sleeps = new Set<() => void>();\n const backoffs = new Set<() => void>();\n const wait = (ms: number, into: Set<() => void>): Promise<void> =>\n stopped\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n let cancel: Cancel = () => {};\n const done = (): void => {\n if (!into.delete(done)) return;\n cancel();\n resolve();\n };\n into.add(done);\n if (Number.isFinite(ms)) cancel = clock.after(ms, done);\n });\n return {\n get wakes() {\n return wakes;\n },\n sleep(ms, since) {\n if (since !== wakes) return Promise.resolve();\n return wait(ms, sleeps);\n },\n backoff(ms) {\n return wait(ms, backoffs);\n },\n wake() {\n wakes += 1;\n const ended = sleeps.size;\n for (const done of [...sleeps]) done();\n return ended;\n },\n stop() {\n stopped = true;\n for (const done of [...sleeps, ...backoffs]) done();\n },\n };\n};\n\n/** A settled wait tells how a work ended in its bound: it ended, it threw, or the bound came first. */\nexport type Settled = { readonly kind: \"done\" } | { readonly kind: \"failed\"; readonly error: unknown } | { readonly kind: \"bound\" };\n\n/** This function waits for a work until a bound on the clock, in milliseconds. */\nexport const settleWithin = (clock: Clock, ms: number, work: Promise<unknown>): Promise<Settled> =>\n new Promise<Settled>((resolve) => {\n const cancel: Cancel = Number.isFinite(ms) ? clock.after(ms, () => resolve({ kind: \"bound\" })) : () => {};\n work.then(\n () => {\n cancel();\n resolve({ kind: \"done\" });\n },\n (error: unknown) => {\n cancel();\n resolve({ kind: \"failed\", error });\n },\n );\n });\n\n/**\n * This function gives the backoff of the knobs of a loop. The first delay is `retry_base`, and each\n * delay is two times longer, up to `retry_cap`. Each delay has a jitter up to the base, as in the Redis client.\n */\nexport const retryOf = (knobs: KnobRecord, owner: string): Backoff => {\n const base = boundedMillisecondsOf(knobs, \"retry_base\", owner);\n const cap = boundedMillisecondsOf(knobs, \"retry_cap\", owner);\n const backoff: Backoff = { base, factor: 2, cap, jitter: { kind: \"add\", amount: base } };\n const problems = backoffProblems(backoff);\n if (problems.length > 0) throw new Error(`${owner}: the retry_base and retry_cap give no backoff: ${problems.join(\", \")}`);\n return backoff;\n};\n\n/**\n * This function gives the problems of the bounds of a loop in a declaration. The close bound fits\n * in the cap of `close transports`. The bound of a unit fits in the cap of `drain`, or the drain can cut a unit (S6 A10).\n */\nexport const boundProblems = (owner: string, closeBound: number, unitBound: number, description: ServiceDescription): string[] => {\n const capOf = (name: string): number | undefined => {\n const phase = description.shutdown.phases.find((each) => each.name === name);\n return phase === undefined ? undefined : valueIn(phase.cap, \"ms\");\n };\n const found: string[] = [];\n const close = capOf(\"close transports\");\n if (close === undefined) found.push(`${owner} needs the phase \"close transports\" to close`);\n else if (closeBound >= close)\n found.push(`the close_bound of ${owner}, ${closeBound} ms, does not fit in the cap of \"close transports\", ${close} ms`);\n const drain = capOf(\"drain\");\n if (drain === undefined) found.push(`${owner} needs the phase \"drain\" to end its units`);\n else if (!Number.isFinite(unitBound))\n found.push(`the unit_processing_time of ${owner} has no bound, thus the drain can cut a unit at its cap of ${drain} ms`);\n else if (unitBound >= drain)\n found.push(`the unit_processing_time of ${owner}, ${unitBound} ms, does not fit in the cap of \"drain\", ${drain} ms`);\n return found;\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { backoffDelay } from \"./backoff.ts\";\nimport type { Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport { boundedMillisecondsOf, countOf, millisecondsOf } from \"./knobs.ts\";\nimport type { Lifecycle, TransportImpl } from \"./lifecycle.ts\";\nimport type { UnitRequest } from \"./units.ts\";\nimport { boundProblems, flights, retryOf, runUnit, settleWithin, sleeper } from \"./units.ts\";\n\n/**\n * These are the knobs of a worker loop, by the names of the ordering law where the law has them.\n * The loop has no defaults, thus each knob is necessary. A bound that nobody gives is \"infinite\".\n */\nexport interface WorkerKnobs {\n /**\n * This time is the sleep of a lane, from the end of one iteration to the start of the next. A\n * time without a bound starts the next iteration only at `wake()`.\n */\n readonly worker_sleep: Extent;\n /**\n * This time is the most that one iteration can take. At it, the loop aborts the signal of the\n * iteration, and a throw after it is a failure. The law reads it as `unit_processing_time@consumer` (O20).\n */\n readonly unit_processing_time: Extent;\n /** This time is the delay after the first failure in sequence. The delay is two times longer after each failure, with a jitter up to this time. */\n readonly retry_base: Quantity;\n /** This time is the most that one delay can be, before its jitter. */\n readonly retry_cap: Quantity;\n /** This time bounds the close: the end of the iterations after their abort, and then the teardown. */\n readonly close_bound: Quantity;\n /** This count (the unit `count`) is the number of lanes. Each lane does its iterations one at a time. */\n readonly concurrency: Quantity;\n /** The other knobs go to the declaration, for example `lease_duration@broker`. The loop does not read them. */\n readonly [knob: string]: Extent;\n}\n\n/** An iteration context is what the loop gives each iteration. */\nexport interface IterationContext<S> {\n /** This signal aborts at the cooperative abort of the drain, at the bound of the iteration, and at the close. */\n readonly signal: AbortSignal;\n /** This signal aborts when the intake stops. A long iteration can end at it in its own way. */\n readonly intake: AbortSignal;\n /** This value is the state that the setup gave, or undefined without a setup. */\n readonly state: S;\n /** This number is the lane of the iteration, from 0. */\n readonly lane: number;\n /** This count is the number of failures in sequence of the lane before this iteration. */\n readonly failures: number;\n /** This lifecycle is the lifecycle that the loop got at its start. */\n readonly life: Lifecycle;\n}\n\n/** These options make a worker loop. Each function can give a promise. */\nexport interface WorkerLoopOptions<S> {\n /** This function makes the state of the loop at its start, for example a connection. Its signal is the signal of the service. */\n readonly setup?: ((signal: AbortSignal) => S | PromiseLike<S>) | undefined;\n /**\n * This function does one iteration. When it gives `\"more\"`, the next iteration of its lane starts\n * after a zero sleep on the clock. A throw is a failure, and the lane then waits its backoff.\n */\n readonly iteration: (context: IterationContext<S>) => unknown;\n /** This function releases the state at the close. It occurs each time that the setup started, with undefined after a failed setup. */\n readonly teardown?: ((state: S | undefined) => void | PromiseLike<void>) | undefined;\n /** This clock is the clock of the lifecycle. The sleeps, the backoffs and the bounds use it. The default is `realClock`. */\n readonly clock?: Clock | undefined;\n /** This function gives the random numbers of the jitter, from 0 up to 1. The default is `Math.random`. */\n readonly random?: (() => number) | undefined;\n /**\n * This route puts each iteration through `life.request`: the service then admits it, counts it,\n * drains it and can cut it. The unit of a route function is the number of the lane.\n */\n readonly request?: UnitRequest<number> | undefined;\n /** This function receives each failure, with the count of failures in sequence of its lane. A refusal of the service is a failure too. */\n readonly onError?: ((error: unknown, failures: number) => void) | undefined;\n}\n\n/** A worker loop is a transport of the lifecycle whose work is a loop of iterations (S6 A10). */\nexport interface WorkerLoop extends TransportImpl {\n /** These knobs go to the declaration of the worker: `svc.worker(name, loop.knobs, loop)`. */\n readonly knobs: WorkerKnobs;\n /**\n * This method ends the sleep of each lane at once, for example when new work is ready. It does\n * not end a backoff. It gives false after the intake stops.\n */\n wake(): boolean;\n /** This method gives the problems of the knobs in a declaration: the close bound and the bound of an iteration against the caps. */\n problems(description: ServiceDescription): string[];\n}\n\nconst OWNER = \"workerLoop\";\n\n/**\n * This function makes a worker loop as a transport (S6 A10). It has a setup, an iteration and a\n * teardown, and each lane does its iterations one at a time.\n * - The start does the setup. A failed setup gets its teardown, and the start throws.\n * - The first iteration of each lane comes after the startup ends. Each sleep and each backoff is on the clock.\n * - `stopIntake` starts no new iteration, and it ends each sleep and each backoff.\n * - `drain` waits for each iteration in flight until the deadline, and gives it the cooperative\n * abort. A throw after that abort is not a failure.\n * - `close` aborts each iteration, waits for its end, and does the teardown, all in `close_bound`.\n */\nexport const workerLoop = <S = undefined>(knobs: WorkerKnobs, options: WorkerLoopOptions<S>): WorkerLoop => {\n const sleep = millisecondsOf(knobs, \"worker_sleep\", OWNER);\n const bound = millisecondsOf(knobs, \"unit_processing_time\", OWNER);\n const backoff = retryOf(knobs, OWNER);\n const closeBound = boundedMillisecondsOf(knobs, \"close_bound\", OWNER);\n const lanes = countOf(knobs, \"concurrency\", OWNER);\n if (!Number.isFinite(lanes)) throw new Error(`${OWNER} needs a concurrency with a bound: each lane is a loop`);\n const clock = options.clock ?? realClock;\n const random = options.random ?? Math.random;\n const running = flights(clock);\n const rests = sleeper(clock);\n const intake = new AbortController();\n // the work of each iteration until it ends, also after a cut: the teardown waits for it\n const pending = new Set<Promise<unknown>>();\n let started = false;\n let setup: Promise<S | undefined> | null = null;\n let state: S | undefined;\n let tornDown: Promise<void> | null = null;\n let closing: Promise<void> | null = null;\n\n const report = (error: unknown, failures: number): void => {\n try {\n options.onError?.(error, failures);\n } catch {\n // an error of the hook does not stop the loop\n }\n };\n /** This function does the teardown one time, after the setup ends, and only when the setup started. */\n const teardown = (): Promise<void> => {\n if (tornDown !== null) return tornDown;\n const release = options.teardown;\n const made = setup;\n tornDown =\n made === null || release === undefined\n ? Promise.resolve()\n : made.then(\n (given) => release(given),\n () => release(undefined),\n );\n return tornDown;\n };\n const keep = (work: Promise<unknown>): Promise<unknown> => {\n pending.add(work);\n const forget = (): void => {\n pending.delete(work);\n };\n work.then(forget, forget);\n return work;\n };\n\n /** This function is one lane: an iteration, then its sleep or its backoff, until the intake stops. */\n const lane = async (index: number, life: Lifecycle): Promise<void> => {\n let failures = 0;\n let since = rests.wakes;\n // the first iteration comes after a zero sleep on the clock: a wake starts it at once\n await rests.sleep(0, since);\n for (;;) {\n if (intake.signal.aborted) return;\n since = rests.wakes;\n const abort = new AbortController();\n const remove = running.add(abort);\n const count = failures;\n const end = await runUnit({\n clock,\n bound,\n abort,\n life,\n request: options.request,\n unit: index,\n work: (signal) =>\n keep(\n (async () =>\n options.iteration({ signal, intake: intake.signal, state: state as S, lane: index, failures: count, life }))(),\n ),\n });\n remove();\n // the shutdown cut the iteration: that is not a failure, and the lane ends (A10)\n if (end.kind === \"cut\") return;\n if (end.kind === \"done\") {\n failures = 0;\n await rests.sleep(end.value === \"more\" ? 0 : sleep, end.value === \"more\" ? rests.wakes : since);\n continue;\n }\n failures += 1;\n report(end.kind === \"failed\" ? end.error : new Error(`the service refused the iteration: ${end.cause}`), failures);\n await rests.backoff(backoffDelay(backoff, failures, random));\n }\n };\n\n return {\n knobs: { ...knobs },\n async start(signal, life) {\n if (closing !== null) throw new Error(`${OWNER}: a closed loop does not start again`);\n if (started) throw new Error(`${OWNER}: the loop started already`);\n started = true;\n const make = options.setup;\n // without a setup function, the setup is empty, and the teardown still occurs at the close\n setup = make === undefined ? Promise.resolve(undefined) : new Promise<S>((resolve) => resolve(make(signal)));\n try {\n await setup.then((given) => {\n state = given;\n });\n } catch (error) {\n // the lifecycle does not close a part that did not start, thus the teardown occurs here (A10)\n await settleWithin(clock, closeBound, teardown());\n throw error;\n }\n // the first iterations wait for the end of the startup, because a request before it gets a refusal\n void life.started.then(() => {\n if (intake.signal.aborted || life.state !== \"running\") return;\n // a lane catches each failure of its work: a rejection here is a defect, and it does not end the process (A5)\n for (let index = 0; index < lanes; index += 1) lane(index, life).catch((error: unknown) => report(error, 0));\n });\n },\n stopIntake() {\n if (intake.signal.aborted) return;\n intake.abort(new Error(`${OWNER} stopped its intake`));\n rests.stop();\n },\n drain(deadline, signal) {\n return running.drain(deadline, signal);\n },\n inFlight: () => running.size,\n wake() {\n if (intake.signal.aborted) return false;\n rests.wake();\n return true;\n },\n close() {\n if (closing !== null) return closing;\n if (!intake.signal.aborted) intake.abort(new Error(`${OWNER} closed`));\n rests.stop();\n running.abort(new Error(`${OWNER} closed`));\n running.clear();\n closing = (async () => {\n const began = clock.now();\n const ended = await settleWithin(clock, closeBound, Promise.allSettled([...pending]));\n // the teardown occurs also after an iteration that did not end, because the setup started (A10)\n const down = await settleWithin(clock, Math.max(0, closeBound - (clock.now() - began)), teardown());\n if (ended.kind === \"bound\")\n throw new Error(`${OWNER}: an iteration did not end in the close_bound of ${closeBound} ms after its abort`);\n if (down.kind === \"failed\") throw down.error;\n if (down.kind === \"bound\") throw new Error(`${OWNER}: the teardown did not end in the close_bound of ${closeBound} ms`);\n })();\n return closing;\n },\n problems(description) {\n return boundProblems(OWNER, closeBound, bound, description);\n },\n };\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { backoffDelay } from \"./backoff.ts\";\nimport type { Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport { boundedMillisecondsOf, countOf, millisecondsOf } from \"./knobs.ts\";\nimport type { Lifecycle, TransportImpl } from \"./lifecycle.ts\";\nimport type { UnitEnd, UnitRequest } from \"./units.ts\";\nimport { boundProblems, flights, retryOf, runUnit, settleWithin, sleeper } from \"./units.ts\";\n\n/**\n * These are the knobs of a queue drain, by the names of the ordering law where the law has them.\n * The drain has no defaults, thus each knob is necessary. A bound that nobody gives is \"infinite\".\n */\nexport interface QueueKnobs {\n /** This time is the wait after a take that gives no job, before the next take. A time without a bound waits for `wake()`. */\n readonly queue_poll_interval: Extent;\n /**\n * This time is the most that one job can take. At it, the drain aborts the signal of the job, and\n * a throw after it is a failure. The law reads it as `unit_processing_time@consumer` (O20).\n */\n readonly unit_processing_time: Extent;\n /** This time is the delay after the first failed take in sequence, or after a refusal of the service. The delay is two times longer after each one. */\n readonly retry_base: Quantity;\n /** This time is the most that one delay can be, before its jitter. */\n readonly retry_cap: Quantity;\n /** This time bounds the close: the end of the jobs after their abort, and then the close of the source. */\n readonly close_bound: Quantity;\n /** This count (the unit `count`) is the most jobs in flight at one time. A count without a bound takes each job that comes. */\n readonly concurrency: Extent;\n /** The other knobs go to the declaration, for example `lease_duration@broker`. The drain does not read them. */\n readonly [knob: string]: Extent;\n}\n\n/**\n * A job source gives the jobs of a queue drain:\n * - A function takes the next job, or gives null when no job is ready. Its signal aborts when the intake stops.\n * - An async iterable gives the jobs in sequence. The drain asks for the next job only when it has a free slot.\n * At the stop of the intake, the drain ends the iterator through `return()`.\n */\nexport type JobSource<J> = ((signal: AbortSignal) => J | null | undefined | PromiseLike<J | null | undefined>) | AsyncIterable<J>;\n\n/**\n * A job action is what the drain does with a job that failed:\n * - `requeue`: the job goes back on the queue.\n * - `reject`: the job leaves the queue without a success, for example to the dead-letter route of the queue.\n * - `ack`: the job leaves the queue, as a poison message does.\n */\nexport type JobAction = \"requeue\" | \"reject\" | \"ack\";\n\n/** A job failure is a job whose handler failed, with the count of its deliveries, 1 at the first. */\nexport interface JobFailure<J> {\n readonly job: J;\n readonly error: unknown;\n readonly delivery: number;\n}\n\n/** A redelivery policy gives the action for a job that failed. The queue declares it, and it has no default (S6 A11). */\nexport type RedeliveryPolicy<J> = (failure: JobFailure<J>) => JobAction;\n\n/**\n * A requeue cause tells why a job goes back on the queue:\n * - `failed`: the redelivery policy sent it back after a failure.\n * - `unstarted`: the drain took the job and did not start it, because its intake stopped or the service refused it.\n * - `cut`: the shutdown cut the job, and its route declares that it can go again.\n */\nexport type RequeueCause = \"failed\" | \"unstarted\" | \"cut\";\n\n/** A job settle is how the drain tells the queue the end of each job. Each function can give a promise. */\nexport interface JobSettle<J> {\n /** This function removes the job from the queue: a success, or the action `ack`. */\n ack(job: J): void | PromiseLike<void>;\n /** This function puts the job back on the queue, or hands it back to the queue at the stop. */\n requeue(job: J, cause: RequeueCause): void | PromiseLike<void>;\n /** This function removes the job from the queue without a success: the action `reject`, or a cut job that cannot go again. */\n reject(job: J, error: unknown): void | PromiseLike<void>;\n /**\n * This function gives the count of deliveries of a job from the queue, 1 at the first. The queue\n * knows it, for example `x-delivery-count` of RabbitMQ or `ApproximateReceiveCount` of SQS. A\n * queue in memory counts for itself. The drain has no default, because a broker gives a new object at each delivery.\n */\n delivery(job: J): number;\n}\n\n/** A job context is what the drain gives the handler of each job. */\nexport interface JobContext {\n /** This signal aborts at the cooperative abort of the drain, at the bound of the job, and at the close. */\n readonly signal: AbortSignal;\n /** This signal aborts when the intake stops. */\n readonly intake: AbortSignal;\n /** This count is the delivery of the job, 1 at the first. */\n readonly delivery: number;\n /** This lifecycle is the lifecycle that the drain got at its start. */\n readonly life: Lifecycle;\n}\n\n/** These options make a queue drain. Each function can give a promise. */\nexport interface QueueDrainOptions<J> {\n readonly source: JobSource<J>;\n /** This function does one job. A throw is a failure, and the redelivery policy then gives its action. */\n readonly handle: (job: J, context: JobContext) => unknown;\n readonly settle: JobSettle<J>;\n /** This policy gives the action for each failed job. `redeliverOnce` gives the policy of S6 A11. */\n readonly redelivery: RedeliveryPolicy<J>;\n /** This function closes the source at the close, after the jobs end: for example, it closes a channel. */\n readonly close?: (() => void | PromiseLike<void>) | undefined;\n /** This clock is the clock of the lifecycle. The polls, the backoffs and the bounds use it. The default is `realClock`. */\n readonly clock?: Clock | undefined;\n /** This function gives the random numbers of the jitter, from 0 up to 1. The default is `Math.random`. */\n readonly random?: (() => number) | undefined;\n /**\n * This route puts each job through `life.request`: the service then admits it, counts it, drains\n * it and can cut it. The idempotency of the route tells if a cut job goes back on the queue.\n */\n readonly request?: UnitRequest<J> | undefined;\n /**\n * This function receives each failure: of a take, of a job, of a settle and of a policy. It also\n * receives the end of a source while the intake is open. The job is undefined for a take and for that end.\n */\n readonly onError?: ((error: unknown, job: J | undefined) => void) | undefined;\n}\n\n/** A queue drain is a transport of the lifecycle whose work is the jobs of a queue (S6 A11). */\nexport interface QueueDrain extends TransportImpl {\n /** These knobs go to the declaration of the consumer: `svc.consumer(name, drain.knobs, drain)`. */\n readonly knobs: QueueKnobs;\n /** This method ends the wait of a poll at once, for example when a job comes. It gives false after the intake stops. */\n wake(): boolean;\n /** This method gives the problems of the knobs in a declaration: the close bound and the bound of a job against the caps. */\n problems(description: ServiceDescription): string[];\n}\n\n/**\n * This function gives the redelivery policy of S6 A11. A poison message gets `ack`. Each other job\n * goes back on the queue after its first failure, one time. After a later failure, `then` gives the\n * action: the declared policy of the queue.\n */\nexport const redeliverOnce =\n <J>(then: JobAction | RedeliveryPolicy<J>, poison?: (error: unknown, job: J) => boolean): RedeliveryPolicy<J> =>\n (failure) => {\n if (poison?.(failure.error, failure.job) === true) return \"ack\";\n if (failure.delivery <= 1) return \"requeue\";\n return typeof then === \"function\" ? then(failure) : then;\n };\n\nconst OWNER = \"queueDrain\";\nconst ACTIONS: readonly string[] = [\"requeue\", \"reject\", \"ack\"];\nconst STOPPED: unique symbol = Symbol(\"the intake stopped\");\n\ntype Taken<J> = { readonly kind: \"job\"; readonly job: J } | { readonly kind: \"none\" } | { readonly kind: \"end\" } | { readonly kind: \"error\"; readonly error: unknown };\n\ninterface Active<J> {\n readonly job: J;\n settled: boolean;\n}\n\nconst isAsyncIterable = (value: unknown): value is AsyncIterable<unknown> =>\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === \"function\";\n\n/**\n * This function makes a queue drain as a transport (S6 A11). One taker takes the jobs from the\n * source while a slot is free, and each job operates in its slot.\n * - A success gets `ack`. A failure gets the action of the redelivery policy.\n * - `stopIntake` takes no new job, and a job that the drain took and did not start goes back (`requeue`, `unstarted`).\n * - `drain` waits for each job in flight until the deadline, and gives it the cooperative abort.\n * - `close` aborts each job, waits for its end, and closes the source, all in `close_bound`. A job\n * that does not end in the bound gets `reject`.\n */\nexport const queueDrain = <J>(knobs: QueueKnobs, options: QueueDrainOptions<J>): QueueDrain => {\n const poll = millisecondsOf(knobs, \"queue_poll_interval\", OWNER);\n const bound = millisecondsOf(knobs, \"unit_processing_time\", OWNER);\n const backoff = retryOf(knobs, OWNER);\n const closeBound = boundedMillisecondsOf(knobs, \"close_bound\", OWNER);\n const concurrency = countOf(knobs, \"concurrency\", OWNER);\n const { settle } = options;\n const clock = options.clock ?? realClock;\n const random = options.random ?? Math.random;\n const running = flights(clock);\n const rests = sleeper(clock);\n const intake = new AbortController();\n const stopped = new Promise<typeof STOPPED>((resolve) =>\n intake.signal.addEventListener(\"abort\", () => resolve(STOPPED), { once: true }),\n );\n // each job until its settle ends, and each job that goes back: the close waits for them\n const pending = new Set<Promise<unknown>>();\n const active = new Set<Active<J>>();\n let refusals = 0;\n let pausedUntil = Number.NEGATIVE_INFINITY;\n let cancelSource: () => void = () => {};\n let started = false;\n let closing: Promise<void> | null = null;\n\n const report = (error: unknown, job: J | undefined): void => {\n try {\n options.onError?.(error, job);\n } catch {\n // an error of the hook does not stop the drain\n }\n };\n const keep = (work: Promise<unknown>): void => {\n pending.add(work);\n const forget = (): void => {\n pending.delete(work);\n };\n work.then(forget, forget);\n };\n /** This function tells the queue the end of a job, one time. A throw of the queue is a failure. */\n const once = async (unit: Active<J>, tell: () => void | PromiseLike<void>): Promise<void> => {\n if (unit.settled) return;\n unit.settled = true;\n try {\n await tell();\n } catch (error) {\n report(error, unit.job);\n }\n };\n const handBack = (job: J): void =>\n keep(\n (async () => {\n try {\n await settle.requeue(job, \"unstarted\");\n } catch (error) {\n report(error, job);\n }\n })(),\n );\n\n /** This function gives the action of the policy for a failed job. A policy that throws, or that gives no action, rejects the job. */\n const actionOf = (job: J, error: unknown, delivery: number): JobAction => {\n try {\n const action = options.redelivery({ job, error, delivery });\n if (ACTIONS.includes(action)) return action;\n report(new Error(`the redelivery policy gave ${String(action)}, not requeue, reject or ack`), job);\n } catch (thrown) {\n report(thrown, job);\n }\n return \"reject\";\n };\n\n const settleEnd = (unit: Active<J>, end: UnitEnd, delivery: number): Promise<void> => {\n const { job } = unit;\n if (end.kind === \"done\") return once(unit, () => settle.ack(job));\n if (end.kind === \"refused\") {\n report(new Error(`the service refused the job: ${end.cause}`), job);\n return once(unit, () => settle.requeue(job, \"unstarted\"));\n }\n if (end.kind === \"cut\") {\n // a cut is not a failure. Only a route that can go again puts the job back (S6 A12)\n if (end.retryable) return once(unit, () => settle.requeue(job, \"cut\"));\n const cut = new Error(end.cause);\n return once(unit, () => settle.reject(job, cut));\n }\n const { error } = end;\n report(error, job);\n const action = actionOf(job, error, delivery);\n if (action === \"requeue\") return once(unit, () => settle.requeue(job, \"failed\"));\n return once(unit, () => (action === \"ack\" ? settle.ack(job) : settle.reject(job, error)));\n };\n\n /** This function starts one job in a slot. The slot stays in flight until the queue has the end of the job. */\n const runJob = (job: J, life: Lifecycle): void => {\n const unit: Active<J> = { job, settled: false };\n active.add(unit);\n const abort = new AbortController();\n const remove = running.add(abort);\n let delivery: number;\n try {\n delivery = settle.delivery(job);\n } catch (error) {\n // a count that the queue cannot give is not a first delivery: the job does not go back for free\n report(error, job);\n delivery = Number.POSITIVE_INFINITY;\n }\n keep(\n (async () => {\n const end = await runUnit({\n clock,\n bound,\n abort,\n life,\n request: options.request,\n unit: job,\n work: (signal) => options.handle(job, { signal, intake: intake.signal, delivery, life }),\n });\n // a refusal of the service stops the takes for a backoff, thus a controller that is not ready does not get each job\n if (end.kind === \"refused\") {\n refusals += 1;\n pausedUntil = clock.now() + backoffDelay(backoff, refusals, random);\n } else refusals = 0;\n await settleEnd(unit, end, delivery);\n })().finally(() => {\n active.delete(unit);\n remove();\n }),\n );\n };\n\n /** This function gives the take of the source. */\n const takeOf = (): (() => Promise<Taken<J>>) => {\n const source = options.source;\n if (isAsyncIterable(source)) {\n const iterator = (source as AsyncIterable<J>)[Symbol.asyncIterator]();\n cancelSource = () => {\n try {\n void Promise.resolve(iterator.return?.()).catch(() => {});\n } catch {\n // an iterator whose return() throws has ended\n }\n };\n return async () => {\n const step = await iterator.next();\n return step.done === true ? { kind: \"end\" } : { kind: \"job\", job: step.value };\n };\n }\n const pull = source as (signal: AbortSignal) => J | null | undefined | PromiseLike<J | null | undefined>;\n return () =>\n new Promise<J | null | undefined>((resolve) => resolve(pull(intake.signal))).then(\n (job): Taken<J> => (job === null || job === undefined ? { kind: \"none\" } : { kind: \"job\", job }),\n );\n };\n\n /** This function is the taker: it takes a job while a slot is free, until the intake stops or the source ends. */\n const taker = async (life: Lifecycle): Promise<void> => {\n const take = takeOf();\n let failures = 0;\n for (;;) {\n if (intake.signal.aborted) return;\n if (running.size >= concurrency) {\n await running.less();\n continue;\n }\n const pause = pausedUntil - clock.now();\n if (pause > 0) {\n await rests.backoff(pause);\n continue;\n }\n const since = rests.wakes;\n const taking = take().catch((error: unknown): Taken<J> => ({ kind: \"error\", error }));\n const first = await Promise.race([taking, stopped]);\n if (first === STOPPED || intake.signal.aborted) {\n // a take that ends after the stop gives a job that the drain does not start: it goes back\n if (first === STOPPED)\n void taking.then((late) => {\n if (late.kind === \"job\") handBack(late.job);\n });\n else if (first.kind === \"job\") handBack(first.job);\n return;\n }\n if (first.kind === \"error\") {\n failures += 1;\n report(first.error, undefined);\n await rests.backoff(backoffDelay(backoff, failures, random));\n continue;\n }\n failures = 0;\n if (first.kind === \"end\") {\n // the source ended while the intake is open: the drain takes no more jobs, thus it says so\n report(new Error(`the source of ${OWNER} ended while its intake was open: it takes no more jobs`), undefined);\n return;\n }\n if (first.kind === \"none\") {\n await rests.sleep(poll, since);\n continue;\n }\n runJob(first.job, life);\n }\n };\n\n const stopTaking = (cause: string): void => {\n if (intake.signal.aborted) return;\n intake.abort(new Error(cause));\n rests.stop();\n running.release();\n cancelSource();\n };\n\n return {\n knobs: { ...knobs },\n start(_signal, life) {\n if (closing !== null) throw new Error(`${OWNER}: a closed drain does not start again`);\n if (started) throw new Error(`${OWNER}: the drain started already`);\n started = true;\n // the first take waits for the end of the startup, because a request before it gets a refusal\n void life.started.then(() => {\n if (intake.signal.aborted || life.state !== \"running\") return;\n // the taker catches each failure of the source: a rejection here is a defect, and it does not end the process (A5)\n taker(life).catch((error: unknown) => report(error, undefined));\n });\n },\n stopIntake() {\n stopTaking(`${OWNER} stopped its intake`);\n },\n drain(deadline, signal) {\n return running.drain(deadline, signal);\n },\n inFlight: () => running.size,\n wake() {\n if (intake.signal.aborted) return false;\n rests.wake();\n return true;\n },\n close() {\n if (closing !== null) return closing;\n stopTaking(`${OWNER} closed`);\n running.abort(new Error(`${OWNER} closed`));\n running.clear();\n closing = (async () => {\n const began = clock.now();\n const ended = await settleWithin(clock, closeBound, Promise.allSettled([...pending]));\n if (ended.kind === \"bound\")\n for (const unit of [...active])\n void once(unit, () => settle.reject(unit.job, new Error(`${OWNER} closed with the job in flight`)));\n const shut = options.close;\n const down = await settleWithin(\n clock,\n Math.max(0, closeBound - (clock.now() - began)),\n shut === undefined ? Promise.resolve() : (async () => shut())(),\n );\n if (ended.kind === \"bound\") throw new Error(`${OWNER}: a job did not end in the close_bound of ${closeBound} ms after its abort`);\n if (down.kind === \"failed\") throw down.error;\n if (down.kind === \"bound\") throw new Error(`${OWNER}: the close of the source did not end in the close_bound of ${closeBound} ms`);\n })();\n return closing;\n },\n problems(description) {\n return boundProblems(OWNER, closeBound, bound, description);\n },\n };\n};\n","import type { Machine, TransitionDef } from \"@mark1russell7/algebra\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport type { MachineName } from \"./events.ts\";\n\n/**\n * The machines of the runtime as `mark1russell7.machine/1` documents. The documents are the\n * specification, and TypeScript implements them. A test records the transitions of the runtime\n * and replays them against each document (`replay` of `@mark1russell7/algebra`), thus the code and\n * the documents cannot disagree.\n */\n\nconst SOURCE = [{ ref: \"packages/service/src (the runtime implements this document)\", rung: \"implemented\" as const }];\nconst base = (id: string, title: string): Pick<Machine, \"format\" | \"id\" | \"title\" | \"layer\" | \"version\" | \"sources\"> => ({\n format: \"mark1russell7.machine/1\",\n id: `service.machine.${id}`,\n title,\n layer: \"self\",\n version: \"0.2.0\",\n sources: SOURCE,\n});\nconst t = (\n id: string,\n from: string | readonly string[],\n on: string | readonly string[],\n to: string,\n extra: Partial<TransitionDef> = {},\n): TransitionDef => ({ id, from, on, to, ...extra });\n\n/**\n * The startup gate opens one time. The lifecycle moves it from `closed` to `starting` while its\n * components start. Then one warm-up sweep of each check opens it. A component that does not start\n * fails it for good.\n */\nexport const GATE_MACHINE: Machine = {\n ...base(\"gate\", \"The startup gate\"),\n states: {\n closed: { initial: true },\n starting: { note: \"the health server, then the dependencies, then the transports\" },\n sweeping: { note: \"one bounded warm-up sweep of each check\" },\n open: { final: true },\n failed: { final: true },\n },\n events: {\n \"startup.begin\": { kind: \"local\" },\n \"component.started\": { kind: \"local\" },\n \"mark-ready\": { kind: \"local\" },\n \"sweep.done\": { kind: \"local\" },\n \"startup.fail\": { kind: \"local\" },\n \"startup.over-budget\": { kind: \"timer\" },\n },\n knobs: { startup: { key: \"policies.startup\", scope: \"service\", unit: \"s\", default: null } },\n timers: {\n startup_budget: {\n duration: { knob: \"startup\", unit: \"s\" },\n arms: [\"enter:closed\"],\n cancels: [\"sweep.done\", \"startup.fail\"],\n fires: \"startup.over-budget\",\n note: \"the gate says that it is over its budget, and the startup probe of the platform acts on it\",\n },\n },\n transitions: [\n t(\"begin\", \"closed\", \"startup.begin\", \"starting\"),\n t(\"component\", \"starting\", \"component.started\", \"starting\"),\n t(\"mark-ready\", [\"closed\", \"starting\"], \"mark-ready\", \"sweeping\"),\n t(\"open\", \"sweeping\", \"sweep.done\", \"open\"),\n t(\"fail\", [\"closed\", \"starting\", \"sweeping\"], \"startup.fail\", \"failed\"),\n // the budget timer leaves each state where it is\n t(\"over-budget-closed\", \"closed\", \"startup.over-budget\", \"closed\", { timer: \"startup_budget\" }),\n t(\"over-budget-starting\", \"starting\", \"startup.over-budget\", \"starting\", { timer: \"startup_budget\" }),\n t(\"over-budget-sweeping\", \"sweeping\", \"startup.over-budget\", \"sweeping\", { timer: \"startup_budget\" }),\n ],\n};\n\n/** A debounce latch counts the polls of its check in sequence. A readiness latch starts tripped. */\nexport const LATCH_MACHINE: Machine = {\n ...base(\"latch\", \"The latch of a policy, as a debounce\"),\n states: {\n tripped: { initial: true, note: \"a readiness latch starts here; a liveness latch starts released\" },\n released: {},\n },\n events: { \"poll.ok\": { kind: \"local\" }, \"poll.fail\": { kind: \"local\" } },\n knobs: {\n fail_after: { key: \"policies.<gate>.failAfter\", scope: \"check\", unit: \"count\", default: null },\n recover_after: { key: \"policies.<gate>.recoverAfter\", scope: \"check\", unit: \"count\", default: null },\n },\n timers: {},\n transitions: [\n t(\"pass\", \"released\", \"poll.ok\", \"released\"),\n t(\"fail-count\", \"released\", \"poll.fail\", \"released\", { guard: \"failures in sequence < fail_after\" }),\n t(\"trip\", \"released\", \"poll.fail\", \"tripped\", { guard: \"failures in sequence >= fail_after\" }),\n t(\"fail\", \"tripped\", \"poll.fail\", \"tripped\"),\n t(\"pass-count\", \"tripped\", \"poll.ok\", \"tripped\", { guard: \"passes in sequence < recover_after\" }),\n t(\"release\", \"tripped\", \"poll.ok\", \"released\", { guard: \"passes in sequence >= recover_after\" }),\n ],\n};\n\n/**\n * A window latch measures time on the monotonic clock from the first failure of a sequence, and\n * from the first pass after a trip.\n */\nexport const WINDOW_MACHINE: Machine = {\n ...base(\"window\", \"The latch of a policy, as a window\"),\n states: {\n released: { initial: true, note: \"a liveness latch starts here; a readiness latch starts tripped\" },\n failing: { note: \"the fail window runs\" },\n tripped: {},\n recovering: { note: \"the recover window runs\" },\n },\n events: {\n \"poll.ok\": { kind: \"local\" },\n \"poll.fail\": { kind: \"local\" },\n \"window.failed\": { kind: \"timer\" },\n \"window.recovered\": { kind: \"timer\" },\n },\n knobs: {\n fail_after: { key: \"policies.<gate>.failAfter\", scope: \"check\", unit: \"s\", default: null },\n recover_after: { key: \"policies.<gate>.recoverAfter\", scope: \"check\", unit: \"s\", default: null },\n },\n timers: {\n fail_window: {\n duration: { knob: \"fail_after\", unit: \"s\" },\n arms: [\"enter:failing\"],\n cancels: [\"poll.ok\"],\n fires: \"window.failed\",\n },\n recover_window: {\n duration: { knob: \"recover_after\", unit: \"s\" },\n arms: [\"enter:recovering\"],\n cancels: [\"poll.fail\"],\n fires: \"window.recovered\",\n },\n },\n transitions: [\n t(\"pass\", \"released\", \"poll.ok\", \"released\"),\n t(\"start-failing\", \"released\", \"poll.fail\", \"failing\", { guard: \"fail_after > 0\" }),\n t(\"trip-at-once\", \"released\", \"poll.fail\", \"tripped\", { guard: \"fail_after = 0\" }),\n t(\"still-failing\", \"failing\", \"poll.fail\", \"failing\"),\n t(\"stop-failing\", \"failing\", \"poll.ok\", \"released\"),\n t(\"trip\", \"failing\", \"window.failed\", \"tripped\", { timer: \"fail_window\" }),\n t(\"fail\", \"tripped\", \"poll.fail\", \"tripped\"),\n t(\"release-at-once\", \"tripped\", \"poll.ok\", \"released\", { guard: \"recover_after is absent or 0\" }),\n t(\"start-recovering\", \"tripped\", \"poll.ok\", \"recovering\", { guard: \"recover_after > 0\" }),\n t(\"still-recovering\", \"recovering\", \"poll.ok\", \"recovering\"),\n t(\"stop-recovering\", \"recovering\", \"poll.fail\", \"tripped\"),\n t(\"release\", \"recovering\", \"window.recovered\", \"released\", { timer: \"recover_window\" }),\n ],\n};\n\n/**\n * A poller starts one check on a jittered loop with a fixed delay. A call that outlives its timeout\n * stays pending (`hung`), and the poller does not start the check again until the call settles.\n */\nexport const POLLER_MACHINE: Machine = {\n ...base(\"poller\", \"The poller of a check\"),\n states: {\n idle: { initial: true, note: \"before the loop starts\" },\n waiting: { note: \"the loop timer runs, and no call is pending\" },\n calling: { note: \"a call runs, in its timeout\" },\n hung: { note: \"a call outlived its timeout, and it is still pending\" },\n stopped: { final: true },\n },\n events: {\n start: { kind: \"local\" },\n sweep: { kind: \"local\" },\n tick: { kind: \"timer\" },\n answer: { kind: \"local\" },\n timeout: { kind: \"timer\" },\n \"late-answer\": { kind: \"local\" },\n stop: { kind: \"local\" },\n },\n knobs: {\n interval: { key: \"checks.<name>.poll.interval\", scope: \"check\", unit: \"s\", default: null },\n timeout: { key: \"checks.<name>.poll.timeout\", scope: \"check\", unit: \"s\", default: null },\n },\n timers: {\n loop: {\n duration: { knob: \"interval\", unit: \"s\" },\n arms: [\"start\", \"tick\"],\n cancels: [\"stop\"],\n fires: \"tick\",\n note: \"the interval, with its jitter: a fixed delay from the start of each poll\",\n },\n poll_timeout: {\n duration: { knob: \"timeout\", unit: \"s\" },\n arms: [\"enter:calling\"],\n cancels: [\"answer\", \"stop\"],\n fires: \"timeout\",\n },\n },\n transitions: [\n t(\"sweep\", \"idle\", \"sweep\", \"calling\"),\n t(\"start\", \"idle\", \"start\", \"waiting\"),\n t(\"start-while-calling\", \"calling\", \"start\", \"calling\", { note: \"a late check polls at once, then starts its loop\" }),\n t(\"start-while-hung\", \"hung\", \"start\", \"hung\"),\n t(\"tick\", \"waiting\", \"tick\", \"calling\", { guard: \"the force-fail list does not name the check\" }),\n t(\"tick-forced\", \"waiting\", \"tick\", \"waiting\", { guard: \"the force-fail list names the check\" }),\n t(\"tick-pending\", \"calling\", \"tick\", \"calling\", { note: \"the poll fails at once: its call is pending\" }),\n t(\"tick-hung\", \"hung\", \"tick\", \"hung\", { note: \"the poll fails at once: its call is pending\" }),\n t(\"answer-loop\", \"calling\", \"answer\", \"waiting\", { guard: \"the loop runs\" }),\n t(\"answer-sweep\", \"calling\", \"answer\", \"idle\", { guard: \"the loop has not started\" }),\n t(\"timeout\", \"calling\", \"timeout\", \"hung\", { timer: \"poll_timeout\" }),\n t(\"late-answer-loop\", \"hung\", \"late-answer\", \"waiting\", { guard: \"the loop runs\" }),\n t(\"late-answer-sweep\", \"hung\", \"late-answer\", \"idle\", { guard: \"the loop has not started\" }),\n t(\"stop\", [\"idle\", \"waiting\", \"calling\", \"hung\"], \"stop\", \"stopped\"),\n t(\"settle-after-stop\", \"stopped\", [\"answer\", \"late-answer\", \"timeout\"], \"stopped\"),\n ],\n};\n\n/**\n * The exit manager is the only part that ends the process. The first exit request starts the\n * shutdown. A later request has no effect, but a repeat signal exits at once when the declaration\n * says `onRepeatSignal: \"exit\"`. The exit code is the code of the exit request, else 1 after an\n * error, else 0.\n */\nexport const EXIT_MACHINE: Machine = {\n ...base(\"exit\", \"The exit manager\"),\n states: { running: { initial: true }, stopping: {}, exited: { final: true } },\n events: {\n \"exit.request\": { kind: \"app\", note: \"SIGINT, SIGTERM, SIGQUIT, a declared process trigger or shutdown()\" },\n \"exit.repeat\": { kind: \"app\", note: \"a trigger or shutdown() while the shutdown runs\" },\n \"startup.fail\": { kind: \"local\" },\n error: { kind: \"local\" },\n \"shutdown.done\": { kind: \"local\" },\n },\n knobs: {\n on_repeat_signal: { key: \"shutdown.onRepeatSignal\", scope: \"service\", unit: null, default: null },\n },\n timers: {},\n transitions: [\n t(\"request\", \"running\", \"exit.request\", \"stopping\"),\n t(\"startup-fail\", \"running\", \"startup.fail\", \"stopping\"),\n t(\"error-running\", \"running\", \"error\", \"running\"),\n t(\"repeat\", \"stopping\", \"exit.repeat\", \"stopping\", {\n guard: \"a process trigger or shutdown() repeats, or a signal repeats and on_repeat_signal is not exit\",\n }),\n t(\"repeat-exit\", \"stopping\", \"exit.repeat\", \"exited\", {\n guard: \"a signal repeats and on_repeat_signal is exit\",\n note: \"the process exits at once with the code 1\",\n }),\n t(\"startup-fail-stopping\", \"stopping\", \"startup.fail\", \"stopping\"),\n t(\"error\", \"stopping\", \"error\", \"stopping\"),\n t(\"exit\", \"stopping\", \"shutdown.done\", \"exited\", {\n note: \"the exit code is the code of the exit request, else 1 after an error, else 0\",\n }),\n ],\n};\n\n/** A watchdog measures how late its own tick comes, and a late tick shows a blocked event loop. */\nexport const WATCHDOG_MACHINE: Machine = {\n ...base(\"watchdog\", \"The watchdog of the event loop\"),\n states: { watching: { initial: true }, blocked: {}, stopped: { final: true } },\n events: { tick: { kind: \"timer\" }, stop: { kind: \"local\" } },\n knobs: {\n tick: { key: \"watchdog.tick\", scope: \"process\", unit: \"s\", default: null },\n threshold: { key: \"watchdog.threshold\", scope: \"process\", unit: \"s\", default: null },\n },\n timers: {\n tick: { duration: { knob: \"tick\", unit: \"s\" }, arms: [\"enter:watching\", \"tick\"], cancels: [\"stop\"], fires: \"tick\" },\n },\n transitions: [\n t(\"on-time\", \"watching\", \"tick\", \"watching\", { guard: \"lateness <= threshold\" }),\n t(\"block\", \"watching\", \"tick\", \"blocked\", { guard: \"lateness > threshold\" }),\n t(\"still-blocked\", \"blocked\", \"tick\", \"blocked\", { guard: \"lateness > threshold\" }),\n t(\"unblock\", \"blocked\", \"tick\", \"watching\", { guard: \"lateness <= threshold\" }),\n t(\"stop\", [\"watching\", \"blocked\"], \"stop\", \"stopped\"),\n ],\n};\n\n/** This function gives the name of a knob for the cap of a phase: `drain` gives `drain_cap`. */\nexport const capKnob = (phase: string): string => `${phase.replace(/[^A-Za-z0-9]+/g, \"_\")}_cap`;\n\n/**\n * This function gives the drain of a declaration as a machine. It has one state for each declared\n * phase, in its sequence, and each state has a timer at its cap. The drain also has the cooperative abort: the\n * cap of the drain less the cooperative window. With the floor `half`, it is half that cap at the\n * least. With the floor `none`, it is 0 at the least.\n */\nexport const drainMachine = (description: ServiceDescription): Machine => {\n const phases = description.shutdown.phases;\n const states: Record<string, { initial?: boolean; final?: boolean; note?: string }> = {\n running: { initial: true },\n };\n for (const phase of phases) states[phase.name] = {};\n states[\"done\"] = { final: true };\n const knobs: Machine[\"knobs\"] = Object.fromEntries([\n ...phases.map((phase) => [\n capKnob(phase.name),\n { key: `shutdown.phases.${phase.name}.cap`, scope: \"service\", unit: \"s\", default: null },\n ]),\n [\"cooperative_window\", { key: \"shutdown.cooperativeWindow\", scope: \"service\", unit: \"s\", default: null }],\n ]);\n const timers: Record<string, Machine[\"timers\"][string]> = {};\n for (const phase of phases)\n timers[`${capKnob(phase.name)}_timer`] = {\n duration: { knob: capKnob(phase.name), unit: \"s\" },\n arms: [`enter:${phase.name}`],\n cancels: [\"phase.done\"],\n fires: \"phase.cap\",\n };\n // the floor of the cooperative abort is half the cap, or 0 for a declaration without a floor\n const floor = description.shutdown.cooperativeFloor === \"none\" ? \"0\" : \"drain_cap / 2\";\n if (phases.some((phase) => phase.name === \"drain\"))\n timers[\"cooperative_abort\"] = {\n duration: { expr: `max(drain_cap - cooperative_window, ${floor})`, unit: \"s\" },\n arms: [\"enter:drain\"],\n cancels: [\"phase.done\", \"phase.cap\"],\n fires: \"drain.cooperative-abort\",\n };\n const transitions: TransitionDef[] = [];\n const order = [\"running\", ...phases.map((phase) => phase.name), \"done\"];\n for (let at = 0; at + 1 < order.length; at += 1) {\n const from = order[at]!;\n const to = order[at + 1]!;\n transitions.push(\n at === 0\n ? t(`begin`, from, \"exit.request\", to)\n : t(`after-${from}`, from, [\"phase.done\", \"phase.cap\"], to, {\n timer: `${capKnob(from)}_timer`,\n note: \"phase.cap: the work of the phase did not end in its cap, and the exit code is 1\",\n }),\n );\n }\n if (phases.some((phase) => phase.name === \"drain\"))\n transitions.push(t(\"cooperative-abort\", \"drain\", \"drain.cooperative-abort\", \"drain\", { timer: \"cooperative_abort\" }));\n // the signal of the service aborts when the sequence passes the poller, or at the end: it leaves\n // the drain where it is\n for (const state of [...phases.map((phase) => phase.name), \"done\"])\n transitions.push(t(`signal-abort-${state}`, state, \"signal.abort\", state));\n return {\n ...base(\"drain\", `The drain of ${description.name}`),\n states,\n events: {\n \"exit.request\": { kind: \"app\" },\n \"phase.done\": { kind: \"local\" },\n \"phase.cap\": { kind: \"timer\" },\n \"drain.cooperative-abort\": { kind: \"timer\" },\n \"signal.abort\": { kind: \"local\" },\n },\n knobs,\n timers,\n transitions,\n };\n};\n\n/** These are the static machines of the runtime, by the name that their events carry. */\nexport const MACHINES: Readonly<Record<Exclude<MachineName, \"drain\" | \"client\">, Machine>> = {\n gate: GATE_MACHINE,\n latch: LATCH_MACHINE,\n window: WINDOW_MACHINE,\n poller: POLLER_MACHINE,\n exit: EXIT_MACHINE,\n watchdog: WATCHDOG_MACHINE,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["message","isAsyncIterable","isTime","boundOf","r","OWNER"],"sources":["../src/description.ts","../src/latch.ts","../src/poller.ts","../src/health.ts","../src/process.ts","../src/routes.ts","../src/requests.ts","../src/lifecycle.ts","../src/watchdog.ts","../src/builder.ts","../src/law.ts","../src/lint.ts","../src/profiles.ts","../src/units.ts","../src/worker.ts","../src/queue.ts","../src/machines.ts"],"sourcesContent":["import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport type { Limiter } from \"./limiter/policy.ts\";\nimport type { Operation } from \"./operation.ts\";\nimport type { ExitSignal, ExitTrigger, MessageShape, ProcessTrigger } from \"./process.ts\";\nimport type { RoutePattern } from \"./routes.ts\";\nimport type { Poll, Timing } from \"./timing.ts\";\n\n/**\n * This is the format of a service as data: what `describe()` exports, and nothing starts. The\n * timer algebra and the ordering law read it. Each timer has a unit. Each knob comes from the\n * declaration, because the runtime has no defaults. A bound that nobody gives is \"no bound\", not\n * zero.\n */\nexport const FORMAT = \"mark1russell7.service/1\";\n\n/** A step is a step of a connection that a check examines. A check that skips a step cannot see a failure in it. */\nexport type Step =\n \"dial\" | \"local-state\" | \"round-trip\" | \"checkout\" | \"progress\" | \"topology\" | \"latency\";\n\n/** A gate is the policy that the failures of a check count toward. */\nexport type Gate = \"readiness\" | \"liveness\";\n\n/** A check is an active check: one signal, for one step of a connection. */\nexport interface Check {\n readonly name: string;\n /** This name is the dependency that it examines, or null when it reads the state of the process. */\n readonly dependency: string | null;\n readonly step: Step;\n /** This flag tells if it uses the connection of the application. A check on its own connection cannot see a failure of that connection. */\n readonly ownConnection: boolean;\n /** This gate is the policy that it controls, or null for a check that only reports. It has no default. */\n readonly gates: Gate | null;\n readonly poll: Poll;\n}\n\n/**\n * A dependency is something that the service uses, with its client. Its knobs have the names that\n * the ordering law uses: `request_timeout`, `connect_bound`, `driver_writeoff_time`,\n * `heartbeat_interval`, `client_retry_window`. Thus the law reads them without a translation.\n */\nexport interface Dependency {\n readonly name: string;\n /** This identifier is the component in the corpus (`systems.component.postgresql`), or null when the corpus does not have it. */\n readonly system: string | null;\n readonly knobs: Readonly<Record<string, Extent>>;\n /**\n * These are the operations that the service does with it, by name (`GET /v1/forecast`, `INCR`).\n * Each operation declares if it can go again. A dependency usually has the two kinds, thus a\n * dependency has no idempotency of its own. An operation without a declaration does not go again.\n */\n readonly operations: Readonly<Record<string, Operation>>;\n}\n\n/**\n * A transport is something that takes work in: a server, a consumer or a worker. Each is a\n * component with a state machine. The service is ready only while each transport takes work.\n */\nexport interface Transport {\n readonly name: string;\n readonly kind: \"server\" | \"consumer\" | \"worker\";\n /** These are its knobs, with the names of the law where the law has them: the `server_idle_close` of a server. */\n readonly knobs: Readonly<Record<string, Extent>>;\n}\n\n/**\n * A controller is a group of routes. It is ready only while the dependencies that it needs are\n * ready. Each route declares if its callers can send it again. When the shutdown stops a request,\n * an idempotent route answers 503, which a caller can retry. Other routes answer 500.\n */\nexport interface Controller {\n readonly name: string;\n readonly requires: readonly string[];\n readonly routes: Readonly<Record<string, Operation>>;\n /**\n * These patterns match the routes that `routes` does not name, in their sequence: the first\n * pattern that matches a route gives its operations. Without a declaration, the controller has\n * no patterns.\n */\n readonly patterns?: readonly RoutePattern[] | undefined;\n}\n\n/** A coupling is a declared edge between two policies. The algebra checks its margin. */\nexport interface Coupling {\n readonly from: Gate;\n readonly to: Gate;\n readonly effect: \"fails\";\n}\n\n/** A phase is one step of the shutdown sequence, with a cap. Its owner adds it. */\nexport interface Phase {\n readonly name: string;\n readonly cap: Quantity;\n}\n\n/**\n * A repeat signal policy tells what an exit signal does while the shutdown runs:\n * - `ignore`: the signal has no effect, and the shutdown continues.\n * - `exit`: the process exits with the code 1 at once, as a second Ctrl-C does in a terminal.\n */\nexport type RepeatSignal = \"ignore\" | \"exit\";\n\n/**\n * A cooperative floor is the earliest time of the cooperative abort in the drain:\n * - `half`: half the cap of the drain. The work in flight gets half the drain at the least.\n * - `none`: no floor. A window of the whole cap or more aborts the work at the start of the drain.\n */\nexport type CooperativeFloor = \"half\" | \"none\";\n\n/** These exit codes replace the code 0 of a clean shutdown, by the trigger of the shutdown. */\nexport type ExitCodes = Readonly<Partial<Record<ExitTrigger, number>>>;\n\n/**\n * A message trigger is a message of the IPC channel that starts the shutdown, for the trigger\n * `ipc-message`. With `as`, the message is that exit signal: it has its exit code and the policy of a\n * repeat signal. Without `as`, the message is the trigger `ipc-message`.\n */\nexport interface MessageTrigger {\n /** This shape is the message that starts the shutdown, for example `\"shutdown\"`. */\n readonly match: MessageShape;\n /** This signal is the exit signal that the message replaces, for example `SIGTERM` on Windows. */\n readonly as?: ExitSignal | undefined;\n}\n\n/** A service description is the whole graph of a service, as data. */\nexport interface ServiceDescription {\n readonly format: typeof FORMAT;\n readonly name: string;\n /** This flag tells if a part joined after the start. That part starts tripped, and the export is partial. */\n readonly partial: boolean;\n readonly transports: readonly Transport[];\n readonly dependencies: readonly Dependency[];\n readonly controllers: readonly Controller[];\n readonly checks: readonly Check[];\n /**\n * These are the keyed limiters of the service, each with its key, its policy, its store and the\n * bound on its keys. Without a declaration, the service has no limiters.\n */\n readonly limiters?: readonly Limiter[] | undefined;\n readonly policies: {\n readonly readiness: Timing;\n readonly liveness: Timing;\n /** This duration is how long the service can take to start. The startup probe must agree with it. */\n readonly startup: Quantity;\n };\n readonly couplings: readonly Coupling[];\n readonly shutdown: {\n readonly phases: readonly Phase[];\n /** This window is how long before the end of the drain the cooperative abort occurs, or no bound. */\n readonly cooperativeWindow: Extent;\n /** This floor is the earliest time of the cooperative abort. Without a declaration, the floor is `half`. */\n readonly cooperativeFloor?: CooperativeFloor | undefined;\n /** This policy tells what a signal does while the shutdown runs. Each declaration gives it, because the runtime has no defaults. */\n readonly onRepeatSignal: RepeatSignal;\n /** These triggers start the shutdown, in addition to the exit signals. Each one is opt-in. */\n readonly triggers?: readonly ProcessTrigger[] | undefined;\n /** These messages of the IPC channel start the shutdown. The trigger `ipc-message` needs one at the least. */\n readonly messages?: readonly MessageTrigger[] | undefined;\n /** These codes replace the exit code 0 by the trigger. Without a code, a clean shutdown exits 0. */\n readonly exitCodes?: ExitCodes | undefined;\n };\n}\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { Timing } from \"./timing.ts\";\n\n/**\n * An outcome is the result of one poll of a check. Only `\"ok\"` passes. An `\"indeterminate\"`\n * outcome measured nothing: it does not pass, and it does not fail.\n */\nexport type Outcome = \"ok\" | \"error\" | \"indeterminate\";\n\n/** A result is one poll of a check, as the runtime records it. */\nexport interface Result {\n readonly outcome: Outcome;\n /** This time is when the result came, on the monotonic clock, in milliseconds. */\n readonly at: number;\n /** This time is how long the poll took, in milliseconds. */\n readonly took: number;\n /** This text tells why the poll did not pass, or it is null. */\n readonly cause: string | null;\n /** This flag tells if the poll failed at its timeout. */\n readonly timedOut: boolean;\n /** This flag tells if the check threw. A throw is an error with a flag. */\n readonly thrown: boolean;\n /** This flag tells if the force-fail list made the poll fail. */\n readonly forced: boolean;\n}\n\n/**\n * A latch turns the results of one check into a verdict, by the timing of its policy. A debounce\n * counts polls in sequence. A window measures time on the monotonic clock from the first failure\n * of a sequence. A tripped latch fails its policy.\n */\nexport interface Latch {\n readonly tripped: boolean;\n /** This time is when the latch last tripped or released. */\n readonly since: number;\n /** This count is the sequence of the latest results: above zero for passes, below zero for failures. */\n readonly streak: number;\n record(result: Result): void;\n /** This method stops the timers of a window. */\n stop(): void;\n}\n\n/**\n * A trace receives each transition of a machine of the runtime: the state before, the state after,\n * and the event. The machine documents of the lifecycle name the same states and events, thus a\n * test can replay a trace against its document.\n */\nexport type Trace = (from: string, to: string, on: string) => void;\n\nconst ms = (amount: { readonly value: number; readonly unit: string }): number =>\n valueIn(amount, \"ms\");\n\n/**\n * This function makes a latch. `tripped` is its state at the start: a readiness latch starts\n * tripped, and a liveness latch starts released. The latch starts `changed` each time it trips or\n * releases, and it gives each transition to `trace`. A debounce has the states `released` and\n * `tripped`. A window also has the states `failing` and `recovering`, while one of its timers runs.\n */\nexport const latch = (\n timing: Timing,\n clock: Clock,\n tripped: boolean,\n changed: () => void,\n trace?: Trace,\n): Latch => {\n let state = tripped;\n let since = clock.now();\n let streak = 0;\n let fails = 0;\n let passes = 0;\n // the timers of a window: the time that a sequence of failures or passes started, and its timer\n let failingSince: number | null = null;\n let passingSince: number | null = null;\n let failTimer: Cancel | null = null;\n let passTimer: Cancel | null = null;\n\n /** This function gives the name of the state, as the machine documents name it. */\n const named = (): string =>\n state\n ? passingSince === null\n ? \"tripped\"\n : \"recovering\"\n : failingSince === null\n ? \"released\"\n : \"failing\";\n /** This function does one step of the machine, and gives its transition to the trace. */\n const step = (on: string, change: () => void): void => {\n const from = named();\n change();\n trace?.(from, named(), on);\n };\n\n const set = (next: boolean): void => {\n if (next === state) return;\n state = next;\n since = clock.now();\n changed();\n };\n const stopFail = (): void => {\n failTimer?.();\n failTimer = null;\n failingSince = null;\n };\n const stopPass = (): void => {\n passTimer?.();\n passTimer = null;\n passingSince = null;\n };\n\n const debounce = (result: Result): void => {\n if (timing.type !== \"debounce\") return;\n if (result.outcome === \"ok\") {\n passes += 1;\n fails = 0;\n if (state && passes >= timing.recoverAfter) set(false);\n } else {\n fails += 1;\n passes = 0;\n if (!state && fails >= timing.failAfter) set(true);\n }\n };\n\n const windowed = (result: Result): void => {\n if (timing.type !== \"window\") return;\n if (result.outcome === \"ok\") {\n stopFail();\n if (!state) return;\n if (timing.recoverAfter === undefined) {\n set(false);\n return;\n }\n if (passingSince !== null) return;\n const wait = ms(timing.recoverAfter);\n if (wait <= 0) {\n stopPass();\n set(false);\n return;\n }\n passingSince = result.at;\n passTimer = clock.after(wait, () =>\n step(\"window.recovered\", () => {\n passTimer = null;\n passingSince = null;\n set(false);\n }),\n );\n return;\n }\n stopPass();\n if (state || failingSince !== null) return;\n const wait = ms(timing.failAfter);\n if (wait <= 0) {\n stopFail();\n set(true);\n return;\n }\n failingSince = result.at;\n failTimer = clock.after(wait, () =>\n step(\"window.failed\", () => {\n failTimer = null;\n failingSince = null;\n set(true);\n }),\n );\n };\n\n return {\n get tripped() {\n return state;\n },\n get since() {\n return since;\n },\n get streak() {\n return streak;\n },\n record(result) {\n // an indeterminate poll measured nothing: it moves no sequence and no streak\n if (result.outcome === \"indeterminate\") return;\n const pass = result.outcome === \"ok\";\n step(pass ? \"poll.ok\" : \"poll.fail\", () => {\n streak = pass ? Math.max(0, streak) + 1 : Math.min(0, streak) - 1;\n debounce(result);\n windowed(result);\n });\n },\n stop() {\n stopFail();\n stopPass();\n },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { Outcome, Result, Trace } from \"./latch.ts\";\nimport type { Poll } from \"./timing.ts\";\n\n/**\n * A check function measures one step of a connection. It ends with nothing or `\"ok\"` for a pass,\n * or with `\"error\"` or `\"indeterminate\"`. A throw is an error with a flag. The runtime aborts the\n * signal at the timeout of the poll.\n */\nexport type CheckFn = (signal: AbortSignal) => Outcome | void | Promise<Outcome | void>;\n\n/** A poller starts one check on its own loop, and gives each result to `record`. */\nexport interface Poller {\n /** This result is the latest one, or null before the first poll. */\n readonly last: Result | null;\n /** This method polls one time at once, outside the loop, and gives the result. */\n pollNow(): Promise<Result>;\n /** This method starts the loop. The first poll of the loop comes after `delay` milliseconds. */\n start(delay: number): void;\n /** This method gives the next delay of the loop: the interval, with the jitter. */\n jittered(): number;\n stop(): void;\n}\n\nexport interface PollerOptions {\n readonly name: string;\n readonly poll: Poll;\n readonly run: CheckFn;\n readonly clock: Clock;\n readonly random: () => number;\n /** This function tells if the force-fail list names the check at this time. */\n readonly forced: () => boolean;\n readonly record: (result: Result) => void;\n /**\n * This function receives each transition of the poller. Its states are `idle`, `waiting`,\n * `calling`, `hung` (a call that outlived its timeout) and `stopped`.\n */\n readonly trace?: Trace | undefined;\n}\n\nconst message = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * This function makes a poller. The loop is on a fixed delay from the start of each poll. Thus the\n * next poll starts one interval after the current poll starts, with the jitter (±20 % is 0.2).\n * The timing algebra of the declaration uses this model.\n *\n * Each poll makes a new measurement. While a use of the check is pending, the poller does not\n * start the check again. Such a poll fails at once with the same cause, and the sequence of\n * failures continues.\n */\nexport const poller = (options: PollerOptions): Poller => {\n const { clock, poll, run } = options;\n const interval = valueIn(poll.interval, \"ms\");\n const timeout = valueIn(poll.timeout, \"ms\");\n let last: Result | null = null;\n let next: Cancel | null = null;\n let stopped = false;\n let looping = false;\n // the call that has not ended, and when it started; `late` once the call outlived its timeout\n let pending: { readonly since: number; late: boolean } | null = null;\n // the polls in flight: stop() ends each one, and its timer\n const active = new Set<() => void>();\n\n /** This function gives the name of the state, as the machine document of the poller names it. */\n const named = (): string =>\n stopped\n ? \"stopped\"\n : pending !== null\n ? pending.late\n ? \"hung\"\n : \"calling\"\n : looping\n ? \"waiting\"\n : \"idle\";\n const step = (on: string, change: () => void): void => {\n const from = named();\n change();\n options.trace?.(from, named(), on);\n };\n\n const result = (\n outcome: Outcome,\n started: number,\n fields: Partial<Pick<Result, \"cause\" | \"timedOut\" | \"thrown\" | \"forced\">> = {},\n ): Result => ({\n outcome,\n at: clock.now(),\n took: clock.now() - started,\n cause: fields.cause ?? null,\n timedOut: fields.timedOut ?? false,\n thrown: fields.thrown ?? false,\n forced: fields.forced ?? false,\n });\n\n const once = (): Promise<Result> => {\n const started = clock.now();\n if (options.forced())\n return Promise.resolve(result(\"error\", started, { cause: \"the force-fail list names it\", forced: true }));\n if (pending !== null) {\n const cause = `its call of ${Math.round(started - pending.since)} ms ago is still pending`;\n return Promise.resolve(result(\"error\", started, { cause }));\n }\n const controller = new AbortController();\n return new Promise<Result>((resolve) => {\n let done = false;\n const finish = (value: Result): void => {\n if (done) return;\n done = true;\n active.delete(abandon);\n cancel();\n resolve(value);\n };\n const abandon = (): void => {\n controller.abort();\n finish(result(\"error\", started, { cause: \"the runtime stopped\" }));\n };\n active.add(abandon);\n const call = { since: started, late: false };\n pending = call;\n const cancel = clock.after(timeout, () => {\n controller.abort();\n // the poll fails at its timeout. The call stays pending until it settles\n step(\"timeout\", () => {\n if (pending === call) call.late = true;\n });\n finish(result(\"error\", started, { cause: `no answer in ${timeout} ms`, timedOut: true }));\n });\n const settled = (): void => {\n if (pending !== call) return;\n step(call.late ? \"late-answer\" : \"answer\", () => {\n pending = null;\n });\n };\n let answer: Promise<Outcome | void>;\n try {\n answer = Promise.resolve(run(controller.signal));\n } catch (error) {\n answer = Promise.reject(error);\n }\n answer.then(\n (value) => {\n settled();\n const outcome = value ?? \"ok\";\n finish(result(outcome, started, outcome === \"ok\" ? {} : { cause: `the check gave ${outcome}` }));\n },\n (error: unknown) => {\n settled();\n finish(result(\"error\", started, { cause: message(error), thrown: true }));\n },\n );\n });\n };\n\n const handle = (value: Result): Result => {\n last = value;\n if (!stopped) options.record(value);\n return value;\n };\n\n const jittered = (): number => interval * (1 + poll.jitter * (2 * options.random() - 1));\n\n const tick = (): void => {\n next = null;\n if (stopped) return;\n let polled: Promise<Result> | undefined;\n step(\"tick\", () => {\n next = clock.after(jittered(), tick);\n polled = once();\n });\n void polled!.then(handle);\n };\n\n return {\n get last() {\n return last;\n },\n pollNow: () => {\n let polled: Promise<Result> | undefined;\n step(\"sweep\", () => {\n polled = once();\n });\n return polled!.then(handle);\n },\n start(delay) {\n if (stopped || next !== null) return;\n step(\"start\", () => {\n looping = true;\n next = clock.after(Math.max(0, delay), tick);\n });\n },\n jittered,\n stop() {\n if (stopped) return;\n step(\"stop\", () => {\n stopped = true;\n next?.();\n next = null;\n });\n for (const abandon of [...active]) abandon();\n },\n };\n};\n","import { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { Check, Gate, ServiceDescription } from \"./description.ts\";\nimport type { MachineName, Recorder } from \"./events.ts\";\nimport type { Latch, Result, Trace } from \"./latch.ts\";\nimport { latch } from \"./latch.ts\";\nimport type { CheckFn, Poller } from \"./poller.ts\";\nimport { poller } from \"./poller.ts\";\n\n/** These options start the runtime. Without them, it uses the real clock and `Math.random`. */\nexport interface StartOptions {\n readonly clock?: Clock | undefined;\n /** This function gives a number in [0, 1) for the jitter of each poll. */\n readonly random?: (() => number) | undefined;\n /** This list names the checks or dependencies whose polls fail at once (a seam for tests). */\n readonly forceFail?: readonly string[] | undefined;\n /** This function receives each transition of each machine of the runtime. */\n readonly record?: Recorder | undefined;\n /**\n * This function can replace the function of a check, for example to add a delay to each call\n * (a seam for tests: a degraded dependency). It gives the function to use.\n */\n readonly wrapCheck?: ((check: Check, run: CheckFn) => CheckFn) | undefined;\n}\n\n/** A check verdict is the cached state of one check, for the probes and the report. */\nexport interface CheckVerdict {\n readonly gates: Gate | null;\n readonly dependency: string | null;\n /** This flag tells if the latch of the check is tripped, or it is null for a check that only reports. */\n readonly tripped: boolean | null;\n readonly streak: number;\n /** This time is when the latch last changed, in milliseconds on the monotonic clock. */\n readonly since: number | null;\n readonly last: Result | null;\n}\n\n/** A verdict is the state of the service, from its cache. Nothing in it starts a check. */\nexport interface HealthVerdict {\n /** This flag becomes true one time, after the warm-up sweep. */\n readonly started: boolean;\n readonly draining: boolean;\n /** This flag tells if the service can take new work: started, not draining, and each readiness latch released. */\n readonly ready: boolean;\n /** This flag tells if each liveness latch is released. */\n readonly alive: boolean;\n /** These flags tell if each controller can take new work, from the dependencies that it needs. */\n readonly controllers: Readonly<Record<string, boolean>>;\n readonly dependencies: Readonly<Record<string, boolean>>;\n readonly checks: Readonly<Record<string, CheckVerdict>>;\n readonly startup: { readonly budget: number; readonly elapsed: number; readonly overBudget: boolean };\n}\n\n/** A probe kind is the question that a probe asks: the startup, the readiness, the liveness, or the whole report. */\nexport type ProbeKind = \"startup\" | \"readiness\" | \"liveness\" | \"report\";\n\n/** A probe answer is a status and a body, for any HTTP framework or none. */\nexport interface ProbeAnswer {\n readonly status: 200 | 503;\n readonly contentType: \"application/health+json\";\n readonly body: {\n readonly status: \"pass\" | \"fail\";\n readonly service: string;\n readonly probe: ProbeKind;\n readonly controller?: string | undefined;\n readonly verdict?: HealthVerdict | undefined;\n };\n}\n\n/** The health runtime of a started service. It reads its timing and its checks from the declaration. */\nexport interface Health {\n verdict(): HealthVerdict;\n /**\n * This method answers a probe from the cache, in constant time, and it starts no check. A\n * readiness probe with a controller asks about that controller. The report always answers 200.\n */\n probe(kind: ProbeKind, controller?: string): ProbeAnswer;\n /** This method gives each change of the verdict to `listener`, and gives the function that stops it. */\n subscribe(listener: (verdict: HealthVerdict) => void): () => void;\n /** This method adds a name to the force-fail list, or removes it. */\n forceFail(name: string, on: boolean): void;\n /** This method fails readiness for good. The drain of the lifecycle starts with it. */\n drain(): void;\n /** This method stops each poller and each timer of the runtime. */\n stop(): void;\n}\n\n/** The runtime parts that the builder and the lifecycle use. */\nexport interface Runtime extends Health {\n /**\n * This method opens the startup gate: one bounded warm-up sweep of each check, then the loops of\n * the pollers. It is idempotent, and it does nothing after `failStartup()` or `stop()`.\n */\n warmUp(): Promise<void>;\n /** This method moves the gate from `closed` to `starting`: the lifecycle starts its components. */\n beginStartup(): void;\n /** This method moves the gate to `failed` for good: a component did not start. */\n failStartup(cause: string): void;\n addCheck(check: Check, run: CheckFn): void;\n addDependency(name: string): void;\n}\n\ninterface Entry {\n readonly check: Check;\n readonly poller: Poller;\n readonly latch: Latch | null;\n}\n\n/**\n * This function makes the runtime of a declaration. The service has no defaults of its own: each\n * timing, poll and coupling comes from the description.\n */\nexport const healthRuntime = (\n description: ServiceDescription,\n runs: ReadonlyMap<string, CheckFn>,\n options: StartOptions = {},\n): Runtime => {\n const clock = options.clock ?? realClock;\n const random = options.random ?? Math.random;\n const forced = new Set(options.forceFail ?? []);\n const startedAt = clock.now();\n const budget = valueIn(description.policies.startup, \"ms\");\n const entries = new Map<string, Entry>();\n const dependencies = new Set(description.dependencies.map((dependency) => dependency.name));\n // a dependency that joined after the start is tripped until a check on it passes one time\n const lateDependencies = new Set<string>();\n const listeners = new Set<(verdict: HealthVerdict) => void>();\n let started = false;\n let draining = false;\n let stopped = false;\n // the startup gate: closed, starting (components start), sweeping (the warm-up), open or failed\n let gate = \"closed\";\n\n const tracer =\n (machine: MachineName, instance: string): Trace =>\n (from, to, on) =>\n options.record?.({ at: clock.now(), machine, instance, from, to, on });\n const gateTrace = tracer(\"gate\", description.name);\n const moveGate = (to: string, on: string, detail?: string): void => {\n const from = gate;\n gate = to;\n options.record?.({\n at: clock.now(),\n machine: \"gate\",\n instance: description.name,\n from,\n to,\n on,\n ...(detail === undefined ? {} : { detail }),\n });\n };\n // the startup budget: a gate that is not open at its end says so. The platform's startup probe\n // acts on it, and the runtime does not stop itself\n let budgetTimer: Cancel | null = clock.after(budget, () => {\n budgetTimer = null;\n if (gate !== \"open\" && gate !== \"failed\") gateTrace(gate, gate, \"startup.over-budget\");\n });\n\n const changed = (): void => {\n if (listeners.size === 0) return;\n const now = verdict();\n for (const listener of listeners) listener(now);\n };\n\n const add = (check: Check, given: CheckFn, late: boolean): void => {\n const run = options.wrapCheck?.(check, given) ?? given;\n const timing = check.gates === null ? null : description.policies[check.gates];\n // readiness is earned: its latch starts tripped. Liveness passes from the start (and a late\n // liveness check starts released too, or one late registration could restart the process)\n const made =\n timing === null\n ? null\n : latch(\n timing,\n clock,\n check.gates === \"readiness\",\n changed,\n tracer(timing.type === \"window\" ? \"window\" : \"latch\", check.name),\n );\n const entry: Entry = {\n check,\n latch: made,\n poller: poller({\n name: check.name,\n poll: check.poll,\n run,\n clock,\n random,\n forced: () =>\n forced.has(check.name) || (check.dependency !== null && forced.has(check.dependency)),\n record: (result) => {\n made?.record(result);\n // a late dependency is released by the first pass of a check on it\n if (result.outcome === \"ok\" && check.dependency !== null)\n if (lateDependencies.delete(check.dependency)) changed();\n },\n trace: tracer(\"poller\", check.name),\n }),\n };\n entries.set(check.name, entry);\n if (late && !stopped) {\n // a late registration pulls readiness until its first pass: it polls at once, then on its loop\n void entry.poller.pollNow();\n entry.poller.start(entry.poller.jittered());\n }\n };\n\n for (const check of description.checks) {\n const run = runs.get(check.name);\n if (run === undefined) throw new Error(`check ${check.name} has no function: the runtime has no defaults`);\n add(check, run, false);\n }\n\n const latchesOf = (gateOf: Gate, keep: (check: Check) => boolean = () => true): Latch[] =>\n [...entries.values()].flatMap((entry) =>\n entry.check.gates === gateOf && entry.latch !== null && keep(entry.check) ? [entry.latch] : [],\n );\n const released = (latches: readonly Latch[]): boolean => latches.every((each) => !each.tripped);\n /** This function tells if a policy fails through a declared coupling from another policy. */\n const coupledOff = (to: Gate, base: Record<Gate, boolean>): boolean =>\n description.couplings.some((coupling) => coupling.to === to && !base[coupling.from]);\n\n const verdict = (): HealthVerdict => {\n const base: Record<Gate, boolean> = {\n readiness: released(latchesOf(\"readiness\")) && lateDependencies.size === 0,\n liveness: released(latchesOf(\"liveness\")),\n };\n const alive = base.liveness && !coupledOff(\"liveness\", base);\n const open = started && !draining && !coupledOff(\"readiness\", base);\n const ready = open && base.readiness;\n const dependencyReady = (name: string): boolean =>\n !lateDependencies.has(name) &&\n released(latchesOf(\"readiness\", (check) => check.dependency === name));\n const own = released(latchesOf(\"readiness\", (check) => check.dependency === null));\n const dependenciesOut: Record<string, boolean> = {};\n for (const name of dependencies) dependenciesOut[name] = dependencyReady(name);\n const controllers: Record<string, boolean> = {};\n for (const controller of description.controllers)\n controllers[controller.name] = open && own && controller.requires.every(dependencyReady);\n const checks: Record<string, CheckVerdict> = {};\n for (const [name, entry] of entries) {\n checks[name] = {\n gates: entry.check.gates,\n dependency: entry.check.dependency,\n tripped: entry.latch?.tripped ?? null,\n streak: entry.latch?.streak ?? 0,\n since: entry.latch?.since ?? null,\n last: entry.poller.last,\n };\n }\n const elapsed = clock.now() - startedAt;\n return {\n started,\n draining,\n ready,\n alive,\n controllers,\n dependencies: dependenciesOut,\n checks,\n startup: { budget, elapsed, overBudget: !started && elapsed > budget },\n };\n };\n\n const answer = (kind: ProbeKind, pass: boolean, controller?: string): ProbeAnswer => ({\n status: pass || kind === \"report\" ? 200 : 503,\n contentType: \"application/health+json\",\n body: {\n status: pass ? \"pass\" : \"fail\",\n service: description.name,\n probe: kind,\n ...(controller === undefined ? {} : { controller }),\n ...(kind === \"report\" ? { verdict: verdict() } : {}),\n },\n });\n\n return {\n verdict,\n probe(kind, controller) {\n const now = verdict();\n if (kind === \"startup\") return answer(kind, now.started);\n if (kind === \"liveness\") return answer(kind, now.alive);\n if (kind === \"report\") return answer(kind, now.ready && now.alive);\n if (controller === undefined) return answer(kind, now.ready);\n const known = now.controllers[controller];\n if (known === undefined) throw new Error(`${description.name} has no controller ${controller}`);\n return answer(kind, known, controller);\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n forceFail(name, on) {\n if (on) forced.add(name);\n else forced.delete(name);\n },\n drain() {\n if (draining) return;\n draining = true;\n changed();\n },\n stop() {\n stopped = true;\n budgetTimer?.();\n budgetTimer = null;\n for (const entry of entries.values()) {\n entry.poller.stop();\n entry.latch?.stop();\n }\n },\n beginStartup() {\n if (gate === \"closed\") moveGate(\"starting\", \"startup.begin\");\n },\n failStartup(cause) {\n if (gate === \"open\" || gate === \"failed\") return;\n moveGate(\"failed\", \"startup.fail\", cause);\n budgetTimer?.();\n budgetTimer = null;\n },\n async warmUp() {\n if (started || stopped || gate === \"failed\" || gate === \"sweeping\") return;\n moveGate(\"sweeping\", \"mark-ready\");\n // one bounded sweep of each check: each poll ends at its timeout at the latest\n const sweep = clock.now();\n await Promise.all([...entries.values()].map((entry) => entry.poller.pollNow()));\n if (stopped || gate !== \"sweeping\") return;\n for (const entry of entries.values())\n entry.poller.start(entry.poller.jittered() - (clock.now() - sweep));\n started = true;\n budgetTimer?.();\n budgetTimer = null;\n moveGate(\"open\", \"sweep.done\");\n changed();\n },\n addCheck(check, run) {\n if (entries.has(check.name)) throw new Error(`${description.name} already has a check named ${check.name}`);\n add(check, run, true);\n changed();\n },\n addDependency(name) {\n if (dependencies.has(name)) return;\n dependencies.add(name);\n lateDependencies.add(name);\n changed();\n },\n };\n};\n","/** An exit signal is a signal that asks the process to stop: each one starts the shutdown. */\nexport type ExitSignal = \"SIGINT\" | \"SIGTERM\" | \"SIGQUIT\";\n\n/** These are the signals that the runtime handles. */\nexport const EXIT_SIGNALS: readonly ExitSignal[] = [\"SIGINT\", \"SIGTERM\", \"SIGQUIT\"];\n\n/**\n * A process trigger is an event of the process, other than a signal, that starts the shutdown. A\n * declaration opts in to each one (`svc.trigger`):\n * - `stdin-close`: the standard input ends or closes, as when the parent of a stdio child goes away.\n * The process must read its input, as a stdio transport does, or Node does not see the end.\n * - `ipc-close`: the IPC channel to the parent process closes.\n * - `ipc-message`: a message on the IPC channel matches a declared shape. Windows cannot give a\n * child a SIGTERM that the child can catch, thus a parent sends a message.\n */\nexport type ProcessTrigger = \"stdin-close\" | \"ipc-close\" | \"ipc-message\";\n\n/** These are the process triggers that a declaration can opt in to. */\nexport const PROCESS_TRIGGERS: readonly ProcessTrigger[] = [\"stdin-close\", \"ipc-close\", \"ipc-message\"];\n\n/** An exit trigger is an event that starts the shutdown: an exit signal, or a declared process trigger. */\nexport type ExitTrigger = ExitSignal | ProcessTrigger;\n\n/** This function tells if a number is an exit code of a process: a whole number from 0 to 255. */\nexport const isExitCode = (code: number): boolean => Number.isInteger(code) && code >= 0 && code <= 255;\n\n/** This function tells if a trigger is an exit signal. A repeat signal obeys `onRepeatSignal`. */\nexport const isExitSignal = (trigger: string): trigger is ExitSignal =>\n (EXIT_SIGNALS as readonly string[]).includes(trigger);\n\n/**\n * A message shape is a value of JSON that a message of the IPC channel can match. A string, a\n * number, a boolean or null matches an equal message. An object matches a message that has each of\n * its fields, and each value of the field matches. An array matches an array of the same length, item by item.\n */\nexport type MessageShape = string | number | boolean | null | readonly MessageShape[] | { readonly [field: string]: MessageShape };\n\n/** This function tells if a value is a message shape: a value of JSON, with no function and no undefined. */\nexport const isMessageShape = (value: unknown): value is MessageShape => {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return true;\n if (typeof value === \"number\") return Number.isFinite(value);\n if (Array.isArray(value)) return value.every(isMessageShape);\n if (typeof value !== \"object\") return false;\n const prototype = Object.getPrototypeOf(value) as unknown;\n return (prototype === Object.prototype || prototype === null) && Object.values(value).every(isMessageShape);\n};\n\n/** This function tells if a message of the IPC channel matches a shape. */\nexport const matchesMessage = (shape: MessageShape, message: unknown): boolean => {\n if (shape === null || typeof shape !== \"object\") return Object.is(shape, message);\n if (Array.isArray(shape)) {\n const items: readonly MessageShape[] = shape;\n return Array.isArray(message) && message.length === items.length && items.every((item, at) => matchesMessage(item, message[at]));\n }\n if (message === null || typeof message !== \"object\" || Array.isArray(message)) return false;\n const fields = message as Readonly<Record<string, unknown>>;\n return Object.entries(shape).every(([field, value]) => Object.hasOwn(fields, field) && matchesMessage(value, fields[field]));\n};\n\n/**\n * A process port is the part of the process that the runtime uses: its exit triggers, its output\n * and its exit. The runtime owns the handlers, because Node as PID 1 without a handler ignores\n * SIGTERM. Only the runtime ends the process, and library code does not. A test gives a fake port,\n * sends triggers, and reads the exit code.\n */\nexport interface ProcessPort {\n /**\n * This method adds a handler for a trigger, and gives the function that removes it. The runtime\n * asks for a process trigger only when the declaration opts in to it. For `ipc-message`, the\n * handler gets each message of the IPC channel, and the runtime matches it.\n */\n on(trigger: ExitTrigger, handler: (message?: unknown) => void): () => void;\n /**\n * This method writes each buffered line of the output, and its promise ends when the output is\n * written. The stage `flush the output` uses it, in the cap of that stage.\n */\n flush?(): Promise<void> | void;\n /**\n * This method keeps the process alive, and gives the function that releases it. The lifecycle\n * holds its process from its start to its exit, as a listening socket does. Thus a process whose\n * timers do not keep it alive does not end in the middle of its work. It keeps its teardown and its exit code.\n */\n hold?(): () => void;\n /** This method ends the process with a code: the code of the exit request, 1 after an error, or 0. */\n exit(code: number): void;\n}\n\n/** A host stream is the part of a stream of Node that the port uses. */\nexport interface HostStream {\n readonly writable?: boolean;\n readonly destroyed?: boolean;\n readonly readableEnded?: boolean;\n write(chunk: string, done: (error?: unknown) => void): boolean;\n on(event: string, handler: () => void): unknown;\n off(event: string, handler: () => void): unknown;\n}\n\n/** A process host is the part of the process of Node that the port uses. Its event `message` gives the message of the IPC channel. */\nexport interface ProcessHost {\n on(signal: string, handler: (message?: unknown) => void): unknown;\n off(signal: string, handler: (message?: unknown) => void): unknown;\n exit(code: number): unknown;\n readonly stdin?: HostStream | undefined;\n readonly stdout?: HostStream | undefined;\n readonly stderr?: HostStream | undefined;\n}\n\n/** This time is the interval of the timer of a hold, the most that a timer of Node accepts. */\nconst HOLD_INTERVAL = 0x7fffffff;\n\n/** This function adds a handler to some events of an emitter. The handler operates one time at most. */\nconst once = (emitter: HostStream | ProcessHost, events: readonly string[], handler: () => void): (() => void) => {\n let called = false;\n const fire = (): void => {\n if (called) return;\n called = true;\n handler();\n };\n for (const event of events) emitter.on(event, fire);\n return () => {\n for (const event of events) emitter.off(event, fire);\n };\n};\n\n/** This function gives a promise that ends when the data before it in a stream is written. */\nconst written = (stream: HostStream | undefined): Promise<void> =>\n new Promise<void>((resolve) => {\n if (stream === undefined || stream.destroyed === true || stream.writable === false) {\n resolve();\n return;\n }\n try {\n // the callback of an empty write comes after each write before it\n stream.write(\"\", () => resolve());\n } catch {\n resolve();\n }\n });\n\n/**\n * This function makes a process port on a host. `find` gives the host at each use, or undefined\n * when the platform has no process. Then the use throws.\n */\nexport const processPortOf = (find: () => ProcessHost | undefined): ProcessPort => {\n const hostProcess = (): ProcessHost => {\n const host = find();\n if (host === undefined) throw new Error(\"no process: give the runtime a process port\");\n return host;\n };\n return {\n on(trigger, handler) {\n const host = hostProcess();\n if (trigger === \"stdin-close\") {\n const input = host.stdin;\n if (input === undefined) return () => {};\n // an input that ended before the handler was added still starts the shutdown\n if (input.readableEnded === true) {\n let live = true;\n queueMicrotask(() => {\n if (live) handler();\n });\n return () => {\n live = false;\n };\n }\n return once(input, [\"end\", \"close\"], handler);\n }\n if (trigger === \"ipc-close\") return once(host, [\"disconnect\"], handler);\n if (trigger === \"ipc-message\") {\n // each message goes to the runtime, which matches it with the declared shapes\n const receive = (message?: unknown): void => handler(message);\n host.on(\"message\", receive);\n return () => {\n host.off(\"message\", receive);\n };\n }\n host.on(trigger, handler);\n return () => {\n host.off(trigger, handler);\n };\n },\n async flush() {\n const host = hostProcess();\n await Promise.all([written(host.stdout), written(host.stderr)]);\n },\n hold() {\n hostProcess();\n // one interval that keeps the event loop alive: its timer does nothing, and the release stops it\n const timer = setInterval(() => {}, HOLD_INTERVAL);\n let held = true;\n return () => {\n if (!held) return;\n held = false;\n clearInterval(timer);\n };\n },\n exit(code) {\n hostProcess().exit(code);\n },\n };\n};\n\n/** This port is the process of Node. */\nexport const nodeProcess: ProcessPort = processPortOf(() => (globalThis as { process?: ProcessHost }).process);\n\n/** An embedded process port records the exit code of a lifecycle that does not own its process. */\nexport interface EmbeddedProcess extends ProcessPort {\n /** This code is the code of the exit request of the lifecycle, or null before that request. */\n readonly exitCode: number | null;\n /** This promise ends with the exit code when the lifecycle asks for its exit. */\n readonly exited: Promise<number>;\n}\n\n/**\n * This function gives a process port for a lifecycle in a process that another part owns. That\n * part is a script, a test of an application, or a library entry. The port adds no handler of a signal or of\n * a trigger, it does not hold the process, and its `exit` only records the code. The caller stops\n * the lifecycle with `life.shutdown()`. A process with a service of its own gives its parts to\n * that service, and does not use this port.\n */\nexport const embeddedProcess = (): EmbeddedProcess => {\n let code: number | null = null;\n let resolve: (code: number) => void = () => {};\n const exited = new Promise<number>((done) => {\n resolve = done;\n });\n return {\n on() {\n // the owner of the process keeps its signals and triggers\n return () => {};\n },\n exit(requested) {\n if (code !== null) return;\n code = requested;\n resolve(requested);\n },\n get exitCode() {\n return code;\n },\n exited,\n };\n};\n","import type { Operation } from \"./operation.ts\";\nimport { operationProblems } from \"./operation.ts\";\n\n/**\n * A route pattern matches the routes of a controller that its exact routes do not name. A\n * registry that changes while the service operates, for example a registry of procedures, thus\n * needs no list of routes before the start. The syntax of a pattern:\n * - `*` matches each text, also an empty text and a text with `/`. The pattern `*` alone matches\n * each route.\n * - `:name` matches a text of one character or more without `/`, and gives it in `params.name`.\n * - Each other character matches itself.\n *\n * The declaration names the operations that a request of the pattern can be. Each operation\n * declares its idempotency, as a route does. A function picks the operation of each request.\n */\nexport interface RoutePattern {\n readonly pattern: string;\n /** These are the operations that a request of the pattern can be, by name. */\n readonly operations: Readonly<Record<string, Operation>>;\n}\n\n/** A route request is what the function of a pattern gets for one request. */\nexport interface RouteRequest {\n readonly controller: string;\n readonly route: string;\n /** These are the texts of the `:name` parts of the pattern, by name. */\n readonly params: Readonly<Record<string, string>>;\n /** These are the texts of the `*` parts of the pattern, in their sequence. */\n readonly wildcards: readonly string[];\n /** This value is the detail that the transport gives with the request, or undefined. */\n readonly detail: unknown;\n}\n\n/**\n * An operation choice gives the name of the operation of one request: one of the operations that\n * the pattern declares. Thus the function decides the idempotency of each request, and the\n * declaration keeps each window of a keyed operation as data.\n */\nexport type OperationOf = (request: RouteRequest) => string;\n\n/** A compiled pattern matches a route, and gives the parts of the route that it matched. */\nexport interface CompiledPattern {\n readonly pattern: string;\n match(route: string): { readonly params: Record<string, string>; readonly wildcards: string[] } | null;\n}\n\nconst NAME = /^[A-Za-z_][A-Za-z0-9_]*/;\n\n/** This function gives the problems of the syntax of a pattern: an empty pattern, a part without a name, or a name two times. */\nexport const patternProblems = (owner: string, pattern: string): string[] => {\n const problems: string[] = [];\n if (pattern.length === 0) problems.push(`${owner} has an empty route pattern`);\n const names = new Set<string>();\n for (let at = 0; at < pattern.length; at += 1) {\n if (pattern[at] !== \":\") continue;\n const name = NAME.exec(pattern.slice(at + 1))?.[0];\n if (name === undefined) {\n problems.push(`${owner}'s pattern ${pattern} has a \":\" without a name at ${at}`);\n continue;\n }\n if (names.has(name)) problems.push(`${owner}'s pattern ${pattern} names :${name} two times`);\n names.add(name);\n at += name.length;\n }\n return problems;\n};\n\n/** This function gives the problems of a pattern and of each of its operations, which `describe()` refuses. */\nexport const routePatternProblems = (owner: string, declared: RoutePattern): string[] => {\n const problems = patternProblems(owner, declared.pattern);\n const names = Object.keys(declared.operations);\n if (names.length === 0) problems.push(`${owner}'s pattern ${declared.pattern} declares no operation`);\n for (const name of names)\n problems.push(...operationProblems(owner, `${declared.pattern} (${name})`, declared.operations[name]!));\n return problems;\n};\n\n/** This function compiles a pattern to a matcher. The match must cover the whole route. */\nexport const compilePattern = (pattern: string): CompiledPattern => {\n const kinds: Array<{ kind: \"param\"; name: string } | { kind: \"wildcard\" }> = [];\n let source = \"^\";\n for (let at = 0; at < pattern.length; at += 1) {\n const char = pattern[at]!;\n if (char === \"*\") {\n source += \"([\\\\s\\\\S]*)\";\n kinds.push({ kind: \"wildcard\" });\n continue;\n }\n if (char === \":\") {\n const name = NAME.exec(pattern.slice(at + 1))?.[0];\n if (name !== undefined) {\n source += \"([^/]+)\";\n kinds.push({ kind: \"param\", name });\n at += name.length;\n continue;\n }\n }\n source += char.replace(/[.*+?^${}()|[\\]\\\\/]/g, \"\\\\$&\");\n }\n const matcher = new RegExp(`${source}$`);\n return {\n pattern,\n match(route) {\n const found = matcher.exec(route);\n if (found === null) return null;\n const params: Record<string, string> = {};\n const wildcards: string[] = [];\n kinds.forEach((part, index) => {\n const text = found[index + 1] ?? \"\";\n if (part.kind === \"param\") params[part.name] = text;\n else wildcards.push(text);\n });\n return { params, wildcards };\n },\n };\n};\n","import { quantity } from \"@mark1russell7/quantity\";\nimport type { Clock } from \"./clock.ts\";\nimport type { Controller } from \"./description.ts\";\nimport type { Operation } from \"./operation.ts\";\nimport { mayReissue } from \"./operation.ts\";\nimport type { CompiledPattern, OperationOf } from \"./routes.ts\";\nimport { compilePattern } from \"./routes.ts\";\n\n/**\n * A request end is the one final result of the stream of a request. Its count `delivered` is the\n * number of items that the stream gave before it. An end after the first item is in-band. The\n * transport sent its answer, thus it writes the end as the last line of the stream, not as a status.\n * - `done`: the work gave each of its items.\n * - `failed`: the work failed for a cause of its own. Before the first item, the adapter answers it\n * as it answers any error of the route.\n * - `refused`: the service did not admit the request. A refused request did not start, thus its\n * caller can send it again: 503, retryable.\n * - `cut`: the shutdown stopped the request. Before the first item, a route whose callers can send\n * it again answers 503, retryable, and each other route answers 500. After the first item, the\n * status is null, and the end is in-band.\n */\nexport type RequestEnd =\n | { readonly kind: \"done\"; readonly delivered: number }\n | { readonly kind: \"failed\"; readonly error: unknown; readonly delivered: number }\n | {\n readonly kind: \"refused\";\n readonly status: 503;\n readonly retryable: true;\n readonly cause: string;\n readonly delivered: 0;\n }\n | {\n readonly kind: \"cut\";\n readonly status: 503 | 500 | null;\n readonly retryable: boolean;\n readonly cause: string;\n readonly delivered: number;\n };\n\n/** A request event is one event of the stream of a request: an item, or the one end, which comes last. */\nexport type RequestEvent<T> = { readonly kind: \"item\"; readonly value: T } | RequestEnd;\n\n/**\n * A request stream is what a request comes to: its items, then one end. A unary work gives a stream\n * of one item. The stream gives an item only when its reader asks for the next event. Thus a slow\n * reader slows the work, and the request stays in flight until the work ends. When the reader\n * stops before the end, the work gets its abort and the `return()` of its iterator.\n */\nexport interface RequestStream<T> extends AsyncIterable<RequestEvent<T>> {\n /** This method reads the whole stream, and gives its items and its end. */\n collect(): Promise<{ readonly items: readonly T[]; readonly end: RequestEnd }>;\n}\n\n/**\n * A request work is what a request function gives: one value, or a stream of values. A work that\n * gives an async iterable is a stream, also through a promise. Each other value is a stream of one.\n */\nexport type RequestWork<T> = T | PromiseLike<T> | AsyncIterable<T> | PromiseLike<AsyncIterable<T>>;\n\n/** A request function does the work of one request. It receives a signal that the shutdown aborts. */\nexport type RequestFn<T> = (signal: AbortSignal) => RequestWork<T>;\n\n/** These options go with one request. */\nexport interface RequestOptions {\n /** This value goes to the function of a route pattern, for example the metadata of a procedure. */\n readonly detail?: unknown;\n}\n\n/** A tracker admits requests, counts the requests in flight, and ends what the shutdown cuts. */\nexport interface Tracker {\n request<T>(controller: string, route: string, work: RequestFn<T>, options?: RequestOptions): RequestStream<T>;\n inFlight(controller?: string): number;\n /** This method refuses each later request. */\n stopIntake(): void;\n /** This method aborts the signal of each request in flight, and ends each stream through `return()`: the cooperative abort of the drain. */\n cooperativeAbort(): void;\n /** This method waits until no request is in flight, or until `deadline`. Then it cuts each request that is left. */\n drain(deadline: number): Promise<void>;\n}\n\ninterface InFlight {\n readonly controller: string;\n /** This function aborts the work, and ends its iterator through `return()`. */\n readonly cooperative: () => void;\n /** This function ends the request with a cut, one time. */\n readonly cut: (cause: string) => void;\n}\n\nconst isAsyncIterable = (value: unknown): value is AsyncIterable<unknown> =>\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === \"function\";\nconst isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { then?: unknown }).then === \"function\";\n\n/** This function gives a stream of events from a function that gives the next event. */\nconst streamOf = <T>(next: () => Promise<RequestEvent<T> | null>, stop: () => void): RequestStream<T> => {\n let chain: Promise<unknown> = Promise.resolve();\n const iterator: AsyncIterator<RequestEvent<T>> = {\n next() {\n // a reader that asks again before an answer gets the events in their sequence\n const step = chain.then(next).then((event): IteratorResult<RequestEvent<T>> =>\n event === null ? { value: undefined, done: true } : { value: event, done: false },\n );\n chain = step.catch(() => {});\n return step;\n },\n return() {\n stop();\n return Promise.resolve({ value: undefined, done: true });\n },\n };\n return {\n [Symbol.asyncIterator]: () => iterator,\n async collect() {\n const items: T[] = [];\n for (;;) {\n const step = await iterator.next();\n if (step.done === true) throw new Error(\"the stream ended without its end\");\n if (step.value.kind === \"item\") items.push(step.value.value);\n else return { items, end: step.value };\n }\n },\n };\n};\n\n/**\n * This function makes a tracker. `refuses` gives the reason that the service refuses a new request\n * for a controller at this time, or null when it admits it. `choices` gives the function of each\n * route pattern, by controller and by pattern.\n */\nexport const tracker = (\n controllers: readonly Controller[],\n clock: Clock,\n refuses: (controller: string) => string | null,\n choices: ReadonlyMap<string, ReadonlyMap<string, OperationOf>> = new Map(),\n): Tracker => {\n const byName = new Map(\n controllers.map((controller) => [\n controller.name,\n {\n controller,\n patterns: (controller.patterns ?? []).map((declared) => ({ declared, compiled: compilePattern(declared.pattern) as CompiledPattern })),\n },\n ]),\n );\n const flights = new Set<InFlight>();\n const idle = new Set<() => void>();\n let intake = true;\n\n /** This function gives the operation of a request: its exact route, else the first pattern that matches it. */\n const operationOf = (controller: string, route: string, detail: unknown): Operation => {\n const held = byName.get(controller);\n if (held === undefined) throw new Error(`there is no controller ${controller}`);\n const exact = held.controller.routes[route];\n if (exact !== undefined) return exact;\n for (const { declared, compiled } of held.patterns) {\n const found = compiled.match(route);\n if (found === null) continue;\n const names = Object.keys(declared.operations);\n const choose = choices.get(controller)?.get(declared.pattern);\n const name = choose === undefined ? names[0]! : choose({ controller, route, ...found, detail });\n const operation = declared.operations[name];\n if (operation === undefined)\n throw new Error(`the pattern ${declared.pattern} of ${controller} declares no operation ${String(name)} for ${route}`);\n return operation;\n }\n // a route that nobody declared has no idempotency: the runtime has no defaults\n throw new Error(`controller ${controller} does not declare the route ${route}`);\n };\n\n const settle = (flight: InFlight): void => {\n if (!flights.delete(flight)) return;\n if (flights.size === 0) for (const done of [...idle]) done();\n };\n\n /** This function starts the work of an admitted request, and gives its stream. */\n const open = <T>(controller: string, operation: Operation, work: RequestFn<T>): RequestStream<T> => {\n const started = clock.now();\n const abort = new AbortController();\n let delivered = 0;\n let end: RequestEnd | null = null;\n let ended = false;\n let returned = false;\n let source: AsyncIterator<T> | null = null;\n // a unary work keeps its value until the reader asks for it\n let unary: { readonly value: T } | null = null;\n let interrupt: () => void = () => {};\n const interrupted = new Promise<\"interrupted\">((resolve) => {\n interrupt = () => resolve(\"interrupted\");\n });\n\n const cutEnd = (cause: string): RequestEnd => {\n const since = quantity(Math.max(0, clock.now() - started) / 1000, \"s\");\n const retryable = mayReissue(operation, since);\n return { kind: \"cut\", status: delivered > 0 ? null : retryable ? 503 : 500, retryable, cause, delivered };\n };\n /** This function ends the work of the request: the end is known, and the request leaves the flights. */\n const finish = (given: RequestEnd): void => {\n if (end !== null) return;\n end = given;\n settle(flight);\n interrupt();\n };\n /** This function ends the work after a throw: a failure after the shutdown aborted it is a cut. */\n const failed = (error: unknown): void =>\n finish(abort.signal.aborted ? cutEnd(\"the shutdown aborted it, and it failed\") : { kind: \"failed\", error, delivered });\n const closeSource = (): void => {\n if (source === null || returned) return;\n returned = true;\n try {\n void Promise.resolve(source.return?.()).catch(() => {});\n } catch {\n // an iterator whose return() throws has ended\n }\n };\n const flight: InFlight = {\n controller,\n cooperative: () => {\n abort.abort(new Error(\"the cooperative abort of the drain\"));\n closeSource();\n },\n cut: (cause) => {\n abort.abort(new Error(cause));\n finish(cutEnd(cause));\n closeSource();\n },\n };\n flights.add(flight);\n\n /** This function takes the result of the work: a stream, or one value. */\n const take = (result: unknown): void => {\n if (end !== null) return;\n if (isAsyncIterable(result)) {\n source = (result as AsyncIterable<T>)[Symbol.asyncIterator]();\n // a stream that comes after the cooperative abort ends at once\n if (abort.signal.aborted) closeSource();\n } else {\n unary = { value: result as T };\n // the unary work has ended: its value waits for the reader\n settle(flight);\n }\n };\n let ready: Promise<void>;\n try {\n const result = work(abort.signal);\n if (isAsyncIterable(result) || !isPromiseLike(result)) {\n take(result);\n ready = Promise.resolve();\n } else ready = Promise.resolve(result).then(take, failed);\n } catch (error) {\n failed(error);\n ready = Promise.resolve();\n }\n\n const next = async (): Promise<RequestEvent<T> | null> => {\n if (ended) return null;\n if (end === null) await Promise.race([ready, interrupted]);\n if (end === null && unary !== null) {\n const { value } = unary;\n unary = null;\n delivered = 1;\n end = { kind: \"done\", delivered };\n return { kind: \"item\", value };\n }\n if (end === null && source !== null) {\n const pending = source.next();\n let step: IteratorResult<T> | \"interrupted\";\n try {\n step = await Promise.race([pending, interrupted]);\n } catch (error) {\n failed(error);\n step = \"interrupted\";\n }\n if (step !== \"interrupted\") {\n if (step.done !== true) {\n delivered += 1;\n return { kind: \"item\", value: step.value };\n }\n // a stream that ends after the abort of the shutdown is a cut\n finish(abort.signal.aborted ? cutEnd(\"the shutdown ended the stream\") : { kind: \"done\", delivered });\n }\n }\n ended = true;\n return end!;\n };\n const stop = (): void => {\n // the reader stopped before the end: the work stops too\n if (end === null) {\n abort.abort(new Error(\"the reader stopped the stream\"));\n finish({ kind: \"done\", delivered });\n closeSource();\n }\n ended = true;\n };\n return streamOf(next, stop);\n };\n\n return {\n request<T>(controller: string, route: string, work: RequestFn<T>, options: RequestOptions = {}) {\n const operation = operationOf(controller, route, options.detail);\n const refusal = intake ? refuses(controller) : \"the service stopped its intake\";\n if (refusal !== null) {\n let given = false;\n const refused: RequestEnd = { kind: \"refused\", status: 503, retryable: true, cause: refusal, delivered: 0 };\n return streamOf<T>(\n () => {\n if (given) return Promise.resolve(null);\n given = true;\n return Promise.resolve(refused);\n },\n () => {\n given = true;\n },\n );\n }\n return open(controller, operation, work);\n },\n inFlight(controller) {\n let count = 0;\n for (const flight of flights) if (controller === undefined || flight.controller === controller) count += 1;\n return count;\n },\n stopIntake() {\n intake = false;\n },\n cooperativeAbort() {\n for (const flight of [...flights]) flight.cooperative();\n },\n drain(deadline) {\n if (flights.size === 0) return Promise.resolve();\n return new Promise<void>((resolve) => {\n let finished = false;\n const done = (): void => {\n if (finished) return;\n finished = true;\n idle.delete(done);\n cancel();\n resolve();\n };\n idle.add(done);\n const cancel = clock.after(Math.max(0, deadline - clock.now()), () => {\n for (const flight of [...flights]) flight.cut(\"the drain reached its deadline\");\n done();\n });\n });\n },\n };\n};\n","import type { Extent } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { CooperativeFloor, Phase, ServiceDescription } from \"./description.ts\";\nimport type { MachineName } from \"./events.ts\";\nimport type { Health, Runtime, StartOptions } from \"./health.ts\";\nimport type { ExitTrigger, ProcessPort } from \"./process.ts\";\nimport { EXIT_SIGNALS, isExitCode, isExitSignal, matchesMessage, nodeProcess } from \"./process.ts\";\nimport type { RequestFn, RequestOptions, RequestStream } from \"./requests.ts\";\nimport { tracker } from \"./requests.ts\";\nimport type { OperationOf } from \"./routes.ts\";\n\n/**\n * A transport is a source of work: a server, a consumer or a worker. Each has one contract. It\n * starts, stops its intake, and drains to a deadline without a throw. It counts its work in flight,\n * and it closes. A second close has no effect.\n */\nexport interface TransportImpl {\n /**\n * This method starts the transport. The lifecycle is the object that `run()` gives at the end of\n * the startup. Its request tracking operates from the start: a request before the startup ends\n * gets a retryable refusal, and `keepAlive()` is false. Do not wait for `life.started` here,\n * because the startup waits for this method.\n */\n start(signal: AbortSignal, life: Lifecycle): Promise<void> | void;\n stopIntake(): Promise<void> | void;\n /**\n * This method lets the work in flight end until `deadline` (milliseconds on the monotonic\n * clock). The signal is the cooperative abort, which comes before the deadline.\n */\n drain(deadline: number, signal: AbortSignal): Promise<void> | void;\n inFlight(): number;\n close(): Promise<void> | void;\n}\n\n/** A dependency handle connects to a dependency at the start, and closes the connection at the end. */\nexport interface DependencyHandle {\n connect(signal: AbortSignal): Promise<void> | void;\n close(): Promise<void> | void;\n}\n\n/**\n * A health server answers the probes, on its own port. It starts first, thus the probes answer\n * while the dependencies connect, and it closes last.\n */\nexport interface HealthServer {\n listen(health: Health): Promise<void> | void;\n close(): Promise<void> | void;\n}\n\n/** A phase context is what a phase gives its work: its deadline, its signal and the clock. */\nexport interface PhaseContext {\n /** This time is the end of the cap of the phase, in milliseconds on the monotonic clock. */\n readonly deadline: number;\n /** This signal aborts at the end of the cap of the phase. */\n readonly signal: AbortSignal;\n readonly clock: Clock;\n}\n\n/** A phase work is a step of the shutdown that an owner adds to a phase. */\nexport type PhaseWork = (context: PhaseContext) => Promise<void> | void;\n\n/**\n * These are the stages of the shutdown, in their sequence. A declared phase with one of these\n * names gets the work of the runtime for its stage. A phase with another name gets only the work of\n * its owners.\n * - `fail readiness`: readiness fails at the start of the shutdown. This phase then holds for its\n * cap, while the endpoints of the platform remove the service.\n * - `stop intake`: each transport stops its intake, and new requests get a retryable 503.\n * - `drain`: the transports and the requests in flight end, until the cap. The cooperative abort\n * comes before the end of the cap, by the cooperative window.\n * - `close transports`: each transport closes.\n * - `stop the poller`: each check and watchdog stops. Then the signal of the service aborts.\n * - `tear down dependencies`: each dependency closes, in the reverse sequence of its connection.\n * - `close the health server`: the probes stop.\n * - `flush the output`: the work of the owners of this phase ends, and then the process port\n * writes the buffered output. Without this phase, the process exits without a wait.\n */\nexport const STAGES = [\n \"fail readiness\",\n \"stop intake\",\n \"drain\",\n \"close transports\",\n \"stop the poller\",\n \"tear down dependencies\",\n \"close the health server\",\n \"flush the output\",\n] as const;\n\nexport type Stage = (typeof STAGES)[number];\n\n/** This function gives the place of a stage in the sequence, or -1 for a phase of another name. */\nexport const stageRank = (name: string): number => (STAGES as readonly string[]).indexOf(name);\n\n/** The signal of the service aborts after the poller stops, and before the dependencies close. */\nconst ABORT_AFTER = stageRank(\"stop the poller\");\n\n/**\n * This function gives the time of the cooperative abort, in milliseconds after the drain starts. It\n * is the cap less the cooperative window. With the floor `half`, it is not less than half the cap,\n * and a window without a bound gives half the cap. With the floor `none`, it is not less than 0.\n */\nexport const cooperativeAbortAt = (cap: number, window: Extent, floor: CooperativeFloor = \"half\"): number => {\n const before = window.value === \"infinite\" ? Number.POSITIVE_INFINITY : valueIn(window, \"ms\");\n return Math.max(cap - before, floor === \"none\" ? 0 : cap / 2);\n};\n\n/** These options run the lifecycle. Without them, it uses the real clock and the process of Node. */\nexport interface RunOptions extends StartOptions {\n readonly process?: ProcessPort | undefined;\n}\n\n/** These options go with a request for the shutdown. */\nexport interface ShutdownOptions {\n /**\n * This code is the exit code that the work of the process gives, a whole number from 0 to 255. The\n * first exit request with a code sets it. A code of 0 lets an error make the exit code 1.\n */\n readonly code?: number | undefined;\n}\n\n/** A lifecycle state tells where the service is in its life. */\nexport type LifecycleState = \"starting\" | \"running\" | \"draining\" | \"exited\";\n\n/** The lifecycle of a running service. */\nexport interface Lifecycle {\n readonly health: Health;\n readonly state: LifecycleState;\n /** This code is the exit code, or null before the exit. */\n readonly exitCode: number | null;\n /** These texts are the errors of the lifecycle. An error makes the exit code 1, unless an exit request gives another code. */\n readonly errors: readonly string[];\n /** This promise ends when the startup ends: the service runs, or its startup failed. */\n readonly started: Promise<void>;\n /** This promise gives the exit code when the shutdown ends. */\n readonly done: Promise<number>;\n /** This signal aborts after the poller stops: the background work of the service stops with it. */\n readonly signal: AbortSignal;\n /**\n * This method asks for the shutdown, as an exit signal does. A second request does not start a\n * second shutdown. It can give the exit code, when no request gave one before.\n */\n shutdown(cause?: string, options?: ShutdownOptions): Promise<number>;\n /**\n * This method does one request of a controller, on a route or a route pattern that the controller\n * declares. It gives the stream of the request: each item of the work, then one end. The service\n * refuses the request while it cannot take new work, and the shutdown can cut it. An undeclared\n * route throws, because it has no idempotency.\n */\n request<T>(controller: string, route: string, work: RequestFn<T>, options?: RequestOptions): RequestStream<T>;\n inFlight(controller?: string): number;\n /**\n * This method tells if a response can keep its connection open. It is false while the service is\n * not ready, thus each response then closes its connection.\n */\n keepAlive(): boolean;\n}\n\n/** The parts that the builder gives the lifecycle, beside the declaration. */\nexport interface Components {\n readonly transports: ReadonlyMap<string, TransportImpl>;\n readonly dependencies: ReadonlyMap<string, DependencyHandle>;\n readonly healthServer: HealthServer | null;\n readonly phaseWork: ReadonlyMap<string, readonly PhaseWork[]>;\n /** These are the functions of the route patterns, by controller and by pattern. */\n readonly choices?: ReadonlyMap<string, ReadonlyMap<string, OperationOf>> | undefined;\n /** This function stops the parts that the poller stage stops beside the checks: the watchdogs. */\n readonly stopPollers: () => void;\n}\n\nconst message = (error: unknown): string =>\n error instanceof Error ? error.message : String(error);\n\n/**\n * This function gives the problems of a declaration that the lifecycle cannot start: a stage with\n * work and no declared phase. The runtime has no defaults, thus a transport without a drain phase\n * has no time to drain.\n */\nexport const lifecycleProblems = (description: ServiceDescription, components: Components): string[] => {\n const declared = new Set(description.shutdown.phases.map((phase) => phase.name));\n const needs = (stage: Stage, why: string): string[] =>\n declared.has(stage) ? [] : [`${description.name} has ${why}, thus it declares the phase \"${stage}\"`];\n const problems: string[] = [];\n for (const transport of description.transports)\n if (!components.transports.has(transport.name))\n problems.push(`transport ${transport.name} has no implementation: the runtime has no defaults`);\n if (components.transports.size > 0 || description.controllers.length > 0) {\n problems.push(...needs(\"stop intake\", \"transports or controllers\"));\n problems.push(...needs(\"drain\", \"transports or controllers\"));\n }\n if (components.transports.size > 0) problems.push(...needs(\"close transports\", \"transports\"));\n if (description.checks.length > 0) problems.push(...needs(\"stop the poller\", \"checks\"));\n if (components.dependencies.size > 0) problems.push(...needs(\"tear down dependencies\", \"dependency handles\"));\n if (components.healthServer !== null) problems.push(...needs(\"close the health server\", \"a health server\"));\n return problems;\n};\n\n/**\n * This function starts the lifecycle of a service. The startup has a sequence: the health server\n * first, then each dependency, then each transport, and the startup gate last. A trigger during the\n * startup gets its shutdown after the startup ends. The shutdown does the declared phases in their\n * sequence, each one capped. Only the lifecycle ends the process. Its exit code is the code of the\n * exit request, else 1 after an error, else 0.\n */\nexport const lifecycle = (\n description: ServiceDescription,\n runtime: Runtime,\n components: Components,\n options: RunOptions = {},\n /** This function receives the lifecycle before the startup begins. */\n bind: (life: Lifecycle) => void = () => {},\n): Lifecycle => {\n const clock = options.clock ?? realClock;\n const port = options.process ?? nodeProcess;\n const record = (machine: MachineName, from: string, to: string, on: string, detail?: string): void =>\n options.record?.({\n at: clock.now(),\n machine,\n instance: description.name,\n from,\n to,\n on,\n ...(detail === undefined ? {} : { detail }),\n });\n const service = new AbortController();\n const errors: string[] = [];\n const exitCodes = description.shutdown.exitCodes ?? {};\n const repeatPolicy = description.shutdown.onRepeatSignal;\n let state: LifecycleState = \"starting\";\n let exitCode: number | null = null;\n // the code of the first exit request that gives one\n let requested: number | undefined;\n let intakeStopped = false;\n let shutdownStarted = false;\n let failedStartup = false;\n // the exit manager: running, stopping, exited\n let exitState = \"running\";\n const moveExit = (to: string, on: string, detail?: string): void => {\n record(\"exit\", exitState, to, on, detail);\n exitState = to;\n };\n const fail = (cause: string): void => {\n errors.push(cause);\n // after an exit, the process has ended: the exit manager does not move again\n if (exitState !== \"exited\") record(\"exit\", exitState, exitState, \"error\", cause);\n };\n\n const requests = tracker(description.controllers, clock, (controller) => {\n if (state === \"starting\") return \"the service has not started\";\n if (state === \"exited\") return \"the service has exited\";\n // while it drains and before its intake stops, the service still serves: the platform can\n // still route a request to it until its endpoints update\n if (state === \"draining\") return null;\n return runtime.verdict().controllers[controller] === true ? null : `controller ${controller} is not ready`;\n }, components.choices);\n\n let finish: (code: number) => void = () => {};\n const done = new Promise<number>((resolve) => {\n finish = resolve;\n });\n // what started, thus what the shutdown stops\n let healthListening = false;\n const connected: Array<[string, DependencyHandle]> = [];\n const startedTransports: Array<[string, TransportImpl]> = [];\n // the startup exists before any part starts: a transport that asks for the shutdown in its start waits for it\n let startupEnded: () => void = () => {};\n const startup = new Promise<void>((resolve) => {\n startupEnded = resolve;\n });\n let offs: Array<() => void> = [];\n // the hold of the process, from the start of the lifecycle to its exit\n let release: () => void = () => {};\n\n /** This function ends the process with a code, one time, and removes each handler of a trigger and the hold. */\n const end = (code: number, on: string): void => {\n state = \"exited\";\n exitCode = code;\n for (const off of offs) off();\n offs = [];\n moveExit(\"exited\", on, `exit ${code}`);\n finish(code);\n // the hold ends at the exit, not at the stop of the intake: the drain and the teardown still need the process\n release();\n port.exit(code);\n };\n\n /**\n * This function receives a trigger of the process: the first one starts the shutdown. The cause\n * names the trigger, and a message that stands for a signal tells it.\n */\n const triggered = (trigger: ExitTrigger, cause: string = trigger): void => {\n if (exitState === \"exited\") return;\n if (shutdownStarted || exitState === \"stopping\") {\n // a signal while the shutdown runs obeys the declared policy. Another trigger, for example the\n // end of stdin after a SIGTERM, has no effect\n if (isExitSignal(trigger) && repeatPolicy === \"exit\") {\n fail(`${cause} came again while the shutdown ran, and the declaration exits at once`);\n end(1, \"exit.repeat\");\n return;\n }\n record(\"exit\", exitState, exitState, \"exit.repeat\", cause);\n return;\n }\n const code = exitCodes[trigger];\n void shutdown(cause, code === undefined ? {} : { code });\n };\n const messages = description.shutdown.messages ?? [];\n /** This function receives a message of the IPC channel. The first declared shape that it matches gives its trigger. */\n const received = (message: unknown): void => {\n const found = messages.find((each) => matchesMessage(each.match, message));\n if (found === undefined) return;\n if (found.as === undefined) triggered(\"ipc-message\");\n else triggered(found.as, `${found.as} (a message of the IPC channel)`);\n };\n\n /** This function does the work of one phase, until its cap. It gives true when the work ended in time. */\n const runPhase = async (phase: Phase, hold: boolean, work: ReadonlyArray<(context: PhaseContext) => Promise<void> | void>): Promise<boolean> => {\n const cap = valueIn(phase.cap, \"ms\");\n const deadline = clock.now() + cap;\n const capped = new AbortController();\n const context: PhaseContext = { deadline, signal: capped.signal, clock };\n let pending = work.length;\n const all = Promise.all(\n work.map(async (each) => {\n try {\n await each(context);\n } catch (error) {\n fail(`the phase ${phase.name} failed: ${message(error)}`);\n } finally {\n pending -= 1;\n }\n }),\n );\n let cancelCap: Cancel = () => {};\n const end = new Promise<\"cap\">((resolve) => {\n cancelCap = clock.after(cap, () => resolve(\"cap\"));\n });\n const first = await Promise.race([all.then(() => \"work\" as const), end]);\n if (first === \"work\" && hold) await end;\n cancelCap();\n capped.abort(new Error(`the phase ${phase.name} reached its cap`));\n return pending === 0;\n };\n\n async function shutdown(cause = \"the service asked for it\", request: ShutdownOptions = {}): Promise<number> {\n if (request.code !== undefined && !isExitCode(request.code))\n throw new Error(`${description.name}: the exit code ${request.code} is not a whole number from 0 to 255`);\n if (exitState === \"exited\") return done;\n if (request.code !== undefined && requested === undefined) requested = request.code;\n if (shutdownStarted) {\n if (exitState === \"stopping\") record(\"exit\", exitState, exitState, \"exit.repeat\", cause);\n return done;\n }\n shutdownStarted = true;\n if (exitState === \"running\") moveExit(\"stopping\", \"exit.request\", cause);\n // a trigger during the startup gets its shutdown after the startup ends\n await startup;\n // a repeat signal can end the process while the startup ends: then only the timers stop\n if (exitState === \"exited\") {\n runtime.stop();\n components.stopPollers();\n return exitCode!;\n }\n state = \"draining\";\n runtime.drain();\n let drainState = \"running\";\n const moveDrain = (to: string, on: string, detail?: string): void => {\n record(\"drain\", drainState, to, on, detail);\n drainState = to;\n };\n const abortService = (): void => {\n if (service.signal.aborted) return;\n service.abort(new Error(\"the service stopped\"));\n record(\"drain\", drainState, drainState, \"signal.abort\");\n };\n const phases = description.shutdown.phases;\n let on = \"exit.request\";\n for (const phase of phases) {\n // after a repeat signal ends the process, no phase starts\n if (exitState === \"exited\") break;\n const rank = stageRank(phase.name);\n moveDrain(phase.name, on);\n if (rank > ABORT_AFTER) abortService();\n const work: Array<(context: PhaseContext) => Promise<void> | void> = [];\n const owned = components.phaseWork.get(phase.name) ?? [];\n if (phase.name === \"stop intake\") {\n work.push(() => {\n intakeStopped = true;\n requests.stopIntake();\n });\n for (const [, impl] of startedTransports) work.push(() => impl.stopIntake());\n }\n // the cooperative abort of the drain: the cap less the window, not before the floor. It ends\n // with the phase, thus a drain that ends before it does not abort anything\n let cancelAbort: Cancel = () => {};\n if (phase.name === \"drain\") {\n const cap = valueIn(phase.cap, \"ms\");\n const cooperative = new AbortController();\n const fireAt = cooperativeAbortAt(cap, description.shutdown.cooperativeWindow, description.shutdown.cooperativeFloor);\n cancelAbort = clock.after(fireAt, () => {\n cooperative.abort(new Error(\"the cooperative abort of the drain\"));\n requests.cooperativeAbort();\n record(\"drain\", drainState, drainState, \"drain.cooperative-abort\");\n });\n work.push(({ deadline }) => requests.drain(deadline));\n for (const [, impl] of startedTransports)\n work.push(({ deadline }) => impl.drain(deadline, cooperative.signal));\n }\n if (phase.name === \"close transports\")\n for (const [, impl] of startedTransports) work.push(() => impl.close());\n if (phase.name === \"stop the poller\")\n work.push(() => {\n runtime.stop();\n components.stopPollers();\n });\n if (phase.name === \"tear down dependencies\")\n work.push(async () => {\n for (const [, handle] of [...connected].reverse()) await handle.close();\n });\n if (phase.name === \"close the health server\" && healthListening && components.healthServer !== null) {\n const server = components.healthServer;\n work.push(() => server.close());\n }\n if (phase.name === \"flush the output\")\n // the owners write their last output first (a log or a trace exporter), then the port writes it\n work.push(async (context) => {\n await Promise.all(\n owned.map(async (each) => {\n try {\n await each(context);\n } catch (error) {\n fail(`the phase ${phase.name} failed: ${message(error)}`);\n }\n }),\n );\n await port.flush?.();\n });\n else for (const each of owned) work.push(each);\n const inTime = await runPhase(phase, phase.name === \"fail readiness\", work);\n cancelAbort();\n if (!inTime) fail(`the phase ${phase.name} did not end in its cap of ${valueIn(phase.cap, \"s\")} s`);\n on = inTime ? \"phase.done\" : \"phase.cap\";\n }\n if (exitState !== \"exited\") moveDrain(\"done\", on);\n abortService();\n // a stage that the declaration does not name still stops: the checks, at the end\n runtime.stop();\n components.stopPollers();\n if (!intakeStopped) requests.stopIntake();\n // a repeat signal can end the process during the sequence: then it ended already\n if (exitState === \"exited\") return exitCode!;\n const code = requested !== undefined && requested !== 0 ? requested : errors.length > 0 ? 1 : 0;\n end(code, \"shutdown.done\");\n return code;\n }\n\n const life: Lifecycle = {\n health: runtime,\n get state() {\n return state;\n },\n get exitCode() {\n return exitCode;\n },\n get errors() {\n return [...errors];\n },\n started: startup,\n done,\n signal: service.signal,\n shutdown,\n request: (controller, route, work, request) => requests.request(controller, route, work, request),\n inFlight: (controller) => requests.inFlight(controller),\n keepAlive: () => state === \"running\" && runtime.verdict().ready,\n };\n\n bind(life);\n release = port.hold?.() ?? (() => {});\n offs = [...EXIT_SIGNALS, ...(description.shutdown.triggers ?? [])].map((trigger: ExitTrigger) =>\n port.on(trigger, trigger === \"ipc-message\" ? received : () => triggered(trigger)),\n );\n\n void (async (): Promise<void> => {\n const started = (what: string): void => record(\"gate\", \"starting\", \"starting\", \"component.started\", what);\n try {\n runtime.beginStartup();\n if (components.healthServer !== null) {\n await components.healthServer.listen(runtime);\n healthListening = true;\n started(\"the health server\");\n }\n for (const dependency of description.dependencies) {\n const handle = components.dependencies.get(dependency.name);\n if (handle === undefined) continue;\n await handle.connect(service.signal);\n connected.push([dependency.name, handle]);\n started(`dependency ${dependency.name}`);\n }\n for (const transport of description.transports) {\n const impl = components.transports.get(transport.name)!;\n await impl.start(service.signal, life);\n startedTransports.push([transport.name, impl]);\n started(`${transport.kind} ${transport.name}`);\n }\n await runtime.warmUp();\n if (state === \"starting\") state = \"running\";\n } catch (error) {\n const cause = `the startup failed: ${message(error)}`;\n failedStartup = true;\n runtime.failStartup(cause);\n fail(cause);\n if (exitState === \"running\") moveExit(\"stopping\", \"startup.fail\", cause);\n else if (exitState === \"stopping\") record(\"exit\", exitState, exitState, \"startup.fail\", cause);\n } finally {\n startupEnded();\n }\n })();\n // a failed startup shuts down what started. An exit request during the startup waits for it\n void startup.then(() => {\n if (failedStartup && !shutdownStarted && exitState !== \"exited\") void shutdown(\"the startup failed\");\n });\n\n return life;\n};\n","import type { Quantity } from \"@mark1russell7/quantity\";\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { Gate } from \"./description.ts\";\nimport type { Outcome, Trace } from \"./latch.ts\";\nimport type { Poll } from \"./timing.ts\";\n\n/**\n * A watchdog spec declares a watchdog of the event loop. The service declares it as a check whose\n * function the watchdog gives: the process's own wedge, which a liveness window reads.\n */\nexport interface WatchdogSpec {\n readonly name: string;\n /** This time is the interval of the tick of the watchdog. */\n readonly tick: Quantity;\n /** This time is the most that a tick can be late before the loop counts as blocked. */\n readonly threshold: Quantity;\n /** This gate is the policy that the check controls, or null for a check that only reports. */\n readonly gates: Gate | null;\n readonly poll: Poll;\n}\n\n/**\n * A watchdog measures how late its own tick comes. A blocked event loop delays each timer, thus a\n * tick that comes later than the threshold shows the block. Its states are `watching`, `blocked`\n * and `stopped`.\n */\nexport interface Watchdog {\n /** This function is the check: it fails when a tick since the last poll came late, or the loop is still blocked. */\n readonly check: () => Outcome;\n /** This time is the most that a tick was late, in milliseconds, since the start. */\n readonly worst: number;\n readonly blocked: boolean;\n stop(): void;\n}\n\n/** This function starts a watchdog on a clock. */\nexport const watchdog = (clock: Clock, spec: WatchdogSpec, trace?: Trace): Watchdog => {\n const tick = valueIn(spec.tick, \"ms\");\n const threshold = valueIn(spec.threshold, \"ms\");\n if (!(tick > 0)) throw new RangeError(`watchdog ${spec.name} ticks every ${tick} ms, not above zero`);\n let blocked = false;\n let stopped = false;\n let worst = 0;\n // the worst lateness since the last poll of the check\n let sincePoll = 0;\n let next: Cancel | null = null;\n\n const named = (): string => (stopped ? \"stopped\" : blocked ? \"blocked\" : \"watching\");\n const arm = (): void => {\n const due = clock.now() + tick;\n next = clock.after(tick, () => {\n next = null;\n if (stopped) return;\n const late = Math.max(0, clock.now() - due);\n worst = Math.max(worst, late);\n sincePoll = Math.max(sincePoll, late);\n const from = named();\n blocked = late > threshold;\n trace?.(from, named(), \"tick\");\n arm();\n });\n };\n arm();\n\n return {\n check: () => {\n const failed = blocked || sincePoll > threshold;\n sincePoll = 0;\n return failed ? \"error\" : \"ok\";\n },\n get worst() {\n return worst;\n },\n get blocked() {\n return blocked;\n },\n stop() {\n if (stopped) return;\n const from = named();\n stopped = true;\n next?.();\n next = null;\n trace?.(from, \"stopped\", \"stop\");\n },\n };\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { convertible, valueIn } from \"@mark1russell7/quantity\";\nimport type {\n Check,\n Controller,\n CooperativeFloor,\n Coupling,\n Dependency,\n ExitCodes,\n Gate,\n MessageTrigger,\n Phase,\n RepeatSignal,\n ServiceDescription,\n Transport,\n} from \"./description.ts\";\nimport { FORMAT } from \"./description.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { Health, Runtime, StartOptions } from \"./health.ts\";\nimport type { Limiter, LimiterSpec } from \"./limiter/policy.ts\";\nimport { limiterProblems } from \"./limiter/policy.ts\";\nimport { healthRuntime } from \"./health.ts\";\nimport type {\n Components,\n DependencyHandle,\n HealthServer,\n Lifecycle,\n PhaseWork,\n RunOptions,\n TransportImpl,\n} from \"./lifecycle.ts\";\nimport { STAGES, lifecycle, lifecycleProblems, stageRank } from \"./lifecycle.ts\";\nimport type { Operation } from \"./operation.ts\";\nimport { operationProblems } from \"./operation.ts\";\nimport type { CheckFn } from \"./poller.ts\";\nimport type { ExitTrigger, ProcessTrigger } from \"./process.ts\";\nimport { EXIT_SIGNALS, PROCESS_TRIGGERS, isExitCode, isExitSignal, isMessageShape } from \"./process.ts\";\nimport type { Profile } from \"./profiles.ts\";\nimport type { OperationOf, RoutePattern } from \"./routes.ts\";\nimport { routePatternProblems } from \"./routes.ts\";\nimport type { Timing } from \"./timing.ts\";\nimport type { Watchdog, WatchdogSpec } from \"./watchdog.ts\";\nimport { watchdog } from \"./watchdog.ts\";\n\n/**\n * A service is composed with plain method uses before it starts. The builder is imperative, and\n * it holds static knowledge. The service does not use an `init` function that gives registrations.\n *\n * const svc = service(\"app\");\n * svc.dependency(\"weather\", {\n * system: null,\n * knobs: { request_timeout },\n * operations: { \"GET /v1/forecast\": { idempotent: true } },\n * });\n * svc.controller(\"forecast\").requires(\"weather\").route(\"GET /api/forecast\", { idempotent: true });\n * svc.check({ name: \"weather.round-trip\", dependency: \"weather\", … }, roundTrip);\n * svc.describe(); // the whole graph as data, with nothing started\n * const health = await svc.start();\n *\n * The graph has one source, thus its parts cannot disagree. A dependency or a check can join\n * after the start. It starts tripped, and the export is partial. The runtime has no defaults of\n * its own. Thus `describe()` refuses a service that does not declare a policy, its startup budget\n * or its shutdown, and it tells which. The shutdown includes what a repeat signal does.\n *\n * `start()` starts only the health runtime. `run()` starts the whole lifecycle: the startup in its\n * sequence, the exit signals, the capped phases of the shutdown, and the exit of the process.\n */\nexport interface ControllerBuilder {\n /** This method declares the dependencies that its routes need. The controller is ready only while they are ready. */\n requires(...dependencies: string[]): ControllerBuilder;\n /** This method declares a route that the controller serves, and if its callers can send it again. */\n route(route: string, operation: Operation): ControllerBuilder;\n /**\n * This method declares a route pattern, the operations that its requests can be, and the function\n * that picks the operation of each request. A pattern with one operation needs no function.\n */\n pattern(pattern: string, operations: Readonly<Record<string, Operation>>, operationOf?: OperationOf): ControllerBuilder;\n}\n\n/** A service builder composes a service, gives it as data, and starts it. */\nexport interface ServiceBuilder {\n readonly name: string;\n /** This method declares a dependency, and the handle that connects to it and closes it, if it has one. */\n dependency(name: string, spec: Omit<Dependency, \"name\">, handle?: DependencyHandle): ServiceBuilder;\n /** This method declares a server, and its implementation. `run()` needs the implementation. */\n server(name: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl): ServiceBuilder;\n consumer(name: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl): ServiceBuilder;\n worker(name: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl): ServiceBuilder;\n /** This method gives the server of the probes. It starts first and closes last. */\n healthServer(server: HealthServer): ServiceBuilder;\n /** This method adds work to a declared phase of the shutdown: the owner of the work registers it. */\n onPhase(phase: string, work: PhaseWork): ServiceBuilder;\n /** This method declares a watchdog of the event loop, as a check on the state of the process. */\n watchdog(spec: WatchdogSpec): ServiceBuilder;\n controller(name: string): ControllerBuilder;\n /** This method declares a check, and the function that measures its step. `start()` needs the function. */\n check(check: Check, run?: CheckFn): ServiceBuilder;\n /**\n * This method declares a keyed limiter as data: its key, its policy, its store and the bound on its\n * keys. `describe()` shows it and refuses a part that is absent, because a limiter has no defaults.\n * `keyedLimiter(name, spec, store)` makes its runtime from the same spec.\n */\n limiter(name: string, spec: LimiterSpec): ServiceBuilder;\n readiness(timing: Timing): ServiceBuilder;\n liveness(timing: Timing): ServiceBuilder;\n startup(budget: Quantity): ServiceBuilder;\n couple(coupling: Coupling): ServiceBuilder;\n phase(name: string, cap: Quantity): ServiceBuilder;\n cooperativeWindow(window: Extent): ServiceBuilder;\n /** This method declares the earliest time of the cooperative abort: half the cap of the drain, or no floor. */\n cooperativeFloor(floor: CooperativeFloor): ServiceBuilder;\n /** This method declares what an exit signal does while the shutdown runs: nothing, or an exit at once. */\n onRepeatSignal(policy: RepeatSignal): ServiceBuilder;\n /** This method declares process triggers that start the shutdown, in addition to the exit signals. */\n trigger(...triggers: ProcessTrigger[]): ServiceBuilder;\n /**\n * This method declares a message of the IPC channel that starts the shutdown, as data. With `as`,\n * the message is that exit signal: `svc.trigger(\"ipc-message\", { match: \"shutdown\", as: \"SIGTERM\" })`.\n */\n trigger(trigger: \"ipc-message\", message: MessageTrigger): ServiceBuilder;\n /** This method declares the exit code of a clean shutdown that a trigger starts, in place of 0. */\n exitCode(trigger: ExitTrigger, code: number): ServiceBuilder;\n /** This method declares each field of a profile, as the method of that field does. */\n profile(profile: Profile): ServiceBuilder;\n /** This method gives the service as data, and it starts nothing. */\n describe(): ServiceDescription;\n /**\n * This method closes the composition, starts the health runtime, and gives it after one warm-up\n * sweep of each check. A part that joins after it starts tripped, and it makes the export\n * partial. A second use gives the same runtime.\n */\n start(options?: StartOptions): Promise<Health>;\n /**\n * This method starts the whole lifecycle and gives it when its startup ends: the service operates,\n * or its startup failed and it shuts down. It refuses a declaration that it cannot start: a transport\n * without its implementation, or a stage with work and no declared phase.\n */\n run(options?: RunOptions): Promise<Lifecycle>;\n /**\n * This value is the health runtime from the time that `start()` begins, or null before. Thus the\n * probes can answer during the warm-up sweep: the startup probe fails until the sweep ends.\n */\n readonly health: Health | null;\n /**\n * This value is the lifecycle from the time that `run()` begins, or null before. Its request\n * tracking operates while the transports start, before `run()` gives it.\n */\n readonly lifecycle: Lifecycle | null;\n}\n\nconst isTime = (amount: Extent): boolean => convertible(amount.unit, \"s\");\nconst above = (amount: Extent): boolean =>\n amount.value === \"infinite\" || (isTime(amount) && valueIn(amount as Quantity, \"s\") > 0);\nconst whole = (count: number): boolean => Number.isInteger(count) && count >= 1;\n\n/** This function gives the problems of a timing: a zero interval or count fails decoding. */\nconst timingProblems = (policy: Gate, timing: Timing): string[] => {\n if (timing.type === \"debounce\") {\n const problems: string[] = [];\n if (!above(timing.interval)) problems.push(`the ${policy} debounce polls at an interval that is not above zero`);\n if (!whole(timing.failAfter)) problems.push(`the ${policy} debounce fails after ${timing.failAfter} polls, not a whole number above zero`);\n if (!whole(timing.recoverAfter)) problems.push(`the ${policy} debounce recovers after ${timing.recoverAfter} polls, not a whole number above zero`);\n return problems;\n }\n const negative = (amount: Quantity | undefined): boolean =>\n amount !== undefined && (!isTime(amount) || valueIn(amount, \"s\") < 0);\n return negative(timing.failAfter) || negative(timing.recoverAfter)\n ? [`the ${policy} window is not a time of zero or more`]\n : [];\n};\n\n/** This function gives the problems of the rules of the shutdown: an unknown name, or an exit code that a process cannot give. */\nconst shutdownProblems = (\n floor: CooperativeFloor | undefined,\n repeat: RepeatSignal | undefined,\n triggers: readonly ProcessTrigger[],\n exitCodes: ExitCodes,\n messages: readonly MessageTrigger[],\n): string[] => {\n const problems: string[] = [];\n if (floor !== undefined && floor !== \"half\" && floor !== \"none\")\n problems.push(`the cooperative floor ${String(floor)} is not \"half\" or \"none\"`);\n if (repeat !== undefined && repeat !== \"ignore\" && repeat !== \"exit\")\n problems.push(`the policy of a repeat signal ${String(repeat)} is not \"ignore\" or \"exit\"`);\n for (const trigger of triggers)\n if (!PROCESS_TRIGGERS.includes(trigger))\n problems.push(`the trigger ${String(trigger)} is not a process trigger (${PROCESS_TRIGGERS.join(\", \")})`);\n if (triggers.includes(\"ipc-message\") && messages.length === 0)\n problems.push(`the trigger ipc-message has no message to match: declare it with svc.trigger(\"ipc-message\", { match })`);\n for (const message of messages) {\n if (!isMessageShape(message.match))\n problems.push(`the match of a message trigger is not a value of JSON: ${String(message.match)}`);\n if (message.as !== undefined && !isExitSignal(message.as))\n problems.push(`a message trigger stands for ${String(message.as)}, not an exit signal (${EXIT_SIGNALS.join(\", \")})`);\n }\n for (const [trigger, code] of Object.entries(exitCodes)) {\n const known = (EXIT_SIGNALS as readonly string[]).includes(trigger) || triggers.includes(trigger as ProcessTrigger);\n if (!known) problems.push(`the exit code of ${trigger} names no exit signal and no declared trigger`);\n if (code === undefined || !isExitCode(code))\n problems.push(`the exit code of ${trigger} is ${String(code)}, not a whole number from 0 to 255`);\n }\n return problems;\n};\n\n/** This function starts the composition of a service. */\nexport const service = (name: string): ServiceBuilder => {\n if (name.trim().length === 0) throw new Error(\"a service needs a name\");\n const transports: Transport[] = [];\n const dependencies: Dependency[] = [];\n const controllers: Array<{\n name: string;\n requires: string[];\n routes: Record<string, Operation>;\n patterns: RoutePattern[];\n }> = [];\n // the function of each route pattern, by controller and by pattern\n const choices = new Map<string, Map<string, OperationOf>>();\n const checks: Check[] = [];\n const runs = new Map<string, CheckFn>();\n const limiters: Limiter[] = [];\n const couplings: Coupling[] = [];\n const phases: Phase[] = [];\n let readiness: Timing | undefined;\n let liveness: Timing | undefined;\n let startup: Quantity | undefined;\n let cooperative: Extent | undefined;\n let floor: CooperativeFloor | undefined;\n let repeat: RepeatSignal | undefined;\n const triggers: ProcessTrigger[] = [];\n const messages: MessageTrigger[] = [];\n const exitCodes: Partial<Record<ExitTrigger, number>> = {};\n let started = false;\n let partial = false;\n let runtime: Promise<Health> | undefined;\n let live: Runtime | undefined;\n let running: Promise<Lifecycle> | undefined;\n let life: Lifecycle | undefined;\n const transportImpls = new Map<string, TransportImpl>();\n const handles = new Map<string, DependencyHandle>();\n const phaseWork = new Map<string, PhaseWork[]>();\n const watchdogs: WatchdogSpec[] = [];\n let probes: HealthServer | null = null;\n\n /** This function stops a change to the shape of the service after the start. */\n const composing = (what: string): void => {\n if (started) throw new Error(`${name} has started: ${what} is declared before svc.start()`);\n };\n const once = (list: ReadonlyArray<{ name: string }>, entry: string, what: string): void => {\n if (list.some((held) => held.name === entry))\n throw new Error(`${name} already has a ${what} named ${entry}`);\n };\n const transport =\n (kind: Transport[\"kind\"]) =>\n (entry: string, knobs: Readonly<Record<string, Extent>>, impl?: TransportImpl) => {\n composing(`a ${kind}`);\n once(transports, entry, \"transport\");\n transports.push({ name: entry, kind, knobs: { ...knobs } });\n if (impl !== undefined) transportImpls.set(entry, impl);\n return builder;\n };\n\n /** This function makes the runtime of the declaration: its checks, and a watchdog for each spec. */\n const makeRuntime = (\n options: StartOptions,\n ): { runtime: Runtime; description: ServiceDescription; stopPollers: () => void } => {\n const description = builder.describe();\n const clock = options.clock ?? realClock;\n const dogs: Watchdog[] = [];\n const all = new Map(runs);\n for (const spec of watchdogs) {\n const dog = watchdog(clock, spec, (from, to, on) =>\n options.record?.({ at: clock.now(), machine: \"watchdog\", instance: spec.name, from, to, on }),\n );\n dogs.push(dog);\n all.set(spec.name, () => dog.check());\n }\n const stopPollers = (): void => {\n for (const dog of dogs) dog.stop();\n };\n let made: Runtime;\n try {\n made = healthRuntime(description, all, options);\n } catch (error) {\n stopPollers();\n throw error;\n }\n // the stop of the health runtime also stops the watchdogs\n const runtime: Runtime = {\n ...made,\n stop: () => {\n made.stop();\n stopPollers();\n },\n };\n return { runtime, description, stopPollers };\n };\n\n const builder: ServiceBuilder = {\n name,\n get health() {\n return live ?? null;\n },\n get lifecycle() {\n return life ?? null;\n },\n dependency(entry, spec, handle) {\n once(dependencies, entry, \"dependency\");\n // a dependency that joins after the start has no connection that the lifecycle opens\n if (handle !== undefined && !started) handles.set(entry, handle);\n dependencies.push({\n name: entry,\n ...spec,\n knobs: { ...spec.knobs },\n operations: { ...spec.operations },\n });\n if (started) {\n partial = true;\n live?.addDependency(entry);\n }\n return builder;\n },\n server: transport(\"server\"),\n consumer: transport(\"consumer\"),\n worker: transport(\"worker\"),\n controller(entry) {\n composing(\"a controller\");\n once(controllers, entry, \"controller\");\n const held = {\n name: entry,\n requires: [] as string[],\n routes: {} as Record<string, Operation>,\n patterns: [] as RoutePattern[],\n };\n controllers.push(held);\n const handle: ControllerBuilder = {\n requires(...needed) {\n composing(`what ${entry} requires`);\n held.requires.push(...needed);\n return handle;\n },\n route(served, operation) {\n composing(`${entry}'s routes`);\n if (held.routes[served] !== undefined)\n throw new Error(`${entry} already serves ${served}`);\n held.routes[served] = { ...operation };\n return handle;\n },\n pattern(pattern, operations, operationOf) {\n composing(`${entry}'s route patterns`);\n if (held.patterns.some((each) => each.pattern === pattern))\n throw new Error(`${entry} already has the route pattern ${pattern}`);\n // the function is not data, thus the builder checks it here, and describe() checks the rest\n if (operationOf === undefined && Object.keys(operations).length > 1)\n throw new Error(`${entry}'s pattern ${pattern} has ${Object.keys(operations).length} operations, thus it needs the function that picks one`);\n held.patterns.push({\n pattern,\n operations: Object.fromEntries(Object.entries(operations).map(([name, operation]) => [name, { ...operation }])),\n });\n if (operationOf !== undefined) {\n const mine = choices.get(entry) ?? new Map<string, OperationOf>();\n mine.set(pattern, operationOf);\n choices.set(entry, mine);\n }\n return handle;\n },\n };\n return handle;\n },\n check(check, run) {\n once(checks, check.name, \"check\");\n if (started && run === undefined)\n throw new Error(`check ${check.name} joins after the start, thus it needs its function`);\n checks.push({ ...check });\n if (run !== undefined) runs.set(check.name, run);\n if (started) {\n partial = true;\n live?.addCheck({ ...check, poll: { ...check.poll } }, run!);\n }\n return builder;\n },\n limiter(entry, spec) {\n composing(`the limiter ${entry}`);\n once(limiters, entry, \"limiter\");\n // the spec is data: the builder keeps a copy, and describe() checks each part\n const given = (spec ?? {}) as Partial<LimiterSpec>;\n limiters.push({\n name: entry,\n ...given,\n ...(given.policy === undefined ? {} : { policy: { ...given.policy } }),\n ...(given.store === undefined ? {} : { store: { ...given.store } }),\n ...(given.evict === undefined ? {} : { evict: { ...given.evict } }),\n } as Limiter);\n return builder;\n },\n healthServer(server) {\n composing(\"the health server\");\n if (probes !== null) throw new Error(`${name} already has a health server`);\n probes = server;\n return builder;\n },\n onPhase(phase, work) {\n composing(`work for the phase ${phase}`);\n phaseWork.set(phase, [...(phaseWork.get(phase) ?? []), work]);\n return builder;\n },\n watchdog(spec) {\n composing(`the watchdog ${spec.name}`);\n once(checks, spec.name, \"check\");\n // the watchdog is a check on the state of the process itself, on its own connection\n checks.push({\n name: spec.name,\n dependency: null,\n step: \"local-state\",\n ownConnection: true,\n gates: spec.gates,\n poll: { ...spec.poll },\n });\n watchdogs.push(spec);\n return builder;\n },\n readiness(timing) {\n composing(\"readiness\");\n readiness = timing;\n return builder;\n },\n liveness(timing) {\n composing(\"liveness\");\n liveness = timing;\n return builder;\n },\n startup(budget) {\n composing(\"the startup budget\");\n startup = budget;\n return builder;\n },\n couple(coupling) {\n composing(\"a coupling\");\n couplings.push({ ...coupling });\n return builder;\n },\n phase(entry, cap) {\n composing(\"a shutdown phase\");\n once(phases, entry, \"shutdown phase\");\n phases.push({ name: entry, cap });\n return builder;\n },\n cooperativeWindow(window) {\n composing(\"the cooperative window\");\n cooperative = window;\n return builder;\n },\n cooperativeFloor(given) {\n composing(\"the cooperative floor\");\n floor = given;\n return builder;\n },\n onRepeatSignal(policy) {\n composing(\"the policy of a repeat signal\");\n repeat = policy;\n return builder;\n },\n trigger(...given: ReadonlyArray<ProcessTrigger | MessageTrigger>) {\n composing(\"a trigger\");\n const [first, message] = given;\n if (first === \"ipc-message\" && typeof message === \"object\" && message !== null) {\n if (!triggers.includes(\"ipc-message\")) triggers.push(\"ipc-message\");\n messages.push({ ...message });\n return builder;\n }\n for (const each of given) if (typeof each === \"string\" && !triggers.includes(each)) triggers.push(each);\n return builder;\n },\n exitCode(trigger, code) {\n composing(`the exit code of ${trigger}`);\n exitCodes[trigger] = code;\n return builder;\n },\n profile(given) {\n composing(\"a profile\");\n if (given.readiness !== undefined) builder.readiness(given.readiness);\n if (given.liveness !== undefined) builder.liveness(given.liveness);\n if (given.startup !== undefined) builder.startup(given.startup);\n for (const coupling of given.couplings ?? []) builder.couple(coupling);\n for (const each of given.phases ?? []) builder.phase(each.name, each.cap);\n if (given.cooperativeWindow !== undefined) builder.cooperativeWindow(given.cooperativeWindow);\n if (given.cooperativeFloor !== undefined) builder.cooperativeFloor(given.cooperativeFloor);\n if (given.onRepeatSignal !== undefined) builder.onRepeatSignal(given.onRepeatSignal);\n if (given.triggers !== undefined) builder.trigger(...given.triggers);\n for (const message of given.messages ?? []) builder.trigger(\"ipc-message\", message);\n for (const [trigger, code] of Object.entries(given.exitCodes ?? {}))\n if (code !== undefined) builder.exitCode(trigger as ExitTrigger, code);\n return builder;\n },\n describe() {\n const missing: string[] = [];\n if (readiness === undefined) missing.push(\"readiness (svc.readiness)\");\n if (liveness === undefined) missing.push(\"liveness (svc.liveness)\");\n if (startup === undefined) missing.push(\"a startup budget (svc.startup)\");\n if (phases.length === 0) missing.push(\"its shutdown phases (svc.phase)\");\n if (cooperative === undefined)\n missing.push(\"a cooperative window, or no bound (svc.cooperativeWindow)\");\n if (repeat === undefined)\n missing.push(`what a repeat signal does, \"ignore\" or \"exit\" (svc.onRepeatSignal)`);\n if (missing.length > 0)\n throw new Error(\n `${name} does not declare ${missing.join(\"; \")}: the runtime has no defaults`,\n );\n const known = new Set(dependencies.map((entry) => entry.name));\n const problems: string[] = [];\n const policies: Record<Gate, Timing> = { readiness: readiness!, liveness: liveness! };\n for (const gate of [\"readiness\", \"liveness\"] as const)\n problems.push(...timingProblems(gate, policies[gate]));\n for (const check of checks) {\n if (check.dependency !== null && !known.has(check.dependency)) {\n problems.push(\n `check ${check.name} exercises ${check.dependency}, which is not a dependency`,\n );\n }\n if (!isTime(check.poll.interval) || !isTime(check.poll.timeout)) {\n problems.push(`check ${check.name} polls in a unit that is not a time`);\n } else if (!above(check.poll.interval) || !above(check.poll.timeout)) {\n problems.push(`check ${check.name} polls with an interval or a timeout that is not above zero`);\n }\n if (!(check.poll.jitter >= 0 && check.poll.jitter < 1))\n problems.push(`check ${check.name} has a jitter of ${check.poll.jitter}, not a fraction below 1`);\n // a debounce counts the polls of each check that it gates, thus they poll at its interval\n const timing = check.gates === null ? null : policies[check.gates];\n if (\n timing?.type === \"debounce\" &&\n isTime(check.poll.interval) &&\n above(timing.interval) &&\n valueIn(check.poll.interval, \"s\") !== valueIn(timing.interval, \"s\")\n )\n problems.push(\n `check ${check.name} polls every ${valueIn(check.poll.interval, \"s\")} s, but the ${check.gates} debounce counts polls every ${valueIn(timing.interval, \"s\")} s`,\n );\n }\n for (const controller of controllers) {\n for (const needed of controller.requires) {\n if (!known.has(needed))\n problems.push(\n `controller ${controller.name} requires ${needed}, which is not a dependency`,\n );\n }\n for (const [route, operation] of Object.entries(controller.routes))\n problems.push(...operationProblems(`controller ${controller.name}`, route, operation));\n for (const declared of controller.patterns)\n problems.push(...routePatternProblems(`controller ${controller.name}`, declared));\n }\n for (const limiter of limiters) {\n const { name: entry, ...spec } = limiter;\n problems.push(...limiterProblems(entry, spec));\n if (limiter.store?.kind === \"shared\" && typeof limiter.store.dependency === \"string\" && !known.has(limiter.store.dependency))\n problems.push(`limiter ${entry} keeps its counts in ${limiter.store.dependency}, which is not a dependency`);\n }\n for (const dependency of dependencies)\n for (const [name, operation] of Object.entries(dependency.operations))\n problems.push(...operationProblems(`dependency ${dependency.name}`, name, operation));\n for (const phase of phases)\n if (!isTime(phase.cap)) problems.push(`phase ${phase.name}'s cap is not a time`);\n problems.push(...shutdownProblems(floor, repeat, triggers, exitCodes, messages));\n // the stages of the shutdown keep their sequence: readiness fails first, the health server closes last\n const ranked = phases.map((phase) => phase.name).filter((each) => stageRank(each) >= 0);\n for (let at = 1; at < ranked.length; at += 1)\n if (stageRank(ranked[at]!) < stageRank(ranked[at - 1]!))\n problems.push(\n `the phase \"${ranked[at]!}\" comes after \"${ranked[at - 1]!}\", but the stages go ${STAGES.join(\", \")}`,\n );\n if (problems.length > 0) throw new Error(`${name}: ${problems.join(\"; \")}`);\n const controllersOut: Controller[] = controllers.map((entry) => ({\n name: entry.name,\n requires: [...entry.requires],\n routes: { ...entry.routes },\n ...(entry.patterns.length === 0\n ? {}\n : { patterns: entry.patterns.map((each) => ({ pattern: each.pattern, operations: { ...each.operations } })) }),\n }));\n return {\n format: FORMAT,\n name,\n partial,\n transports: transports.map((entry) => ({ ...entry, knobs: { ...entry.knobs } })),\n dependencies: dependencies.map((entry) => ({\n ...entry,\n knobs: { ...entry.knobs },\n operations: { ...entry.operations },\n })),\n controllers: controllersOut,\n checks: checks.map((entry) => ({ ...entry, poll: { ...entry.poll } })),\n ...(limiters.length === 0\n ? {}\n : {\n limiters: limiters.map((entry) => ({\n ...entry,\n policy: { ...entry.policy },\n store: { ...entry.store },\n evict: { maxKeys: { ...entry.evict.maxKeys } },\n })),\n }),\n policies: { readiness: readiness!, liveness: liveness!, startup: startup! },\n couplings: couplings.map((entry) => ({ ...entry })),\n shutdown: {\n phases: phases.map((entry) => ({ ...entry })),\n cooperativeWindow: cooperative!,\n ...(floor === undefined ? {} : { cooperativeFloor: floor }),\n onRepeatSignal: repeat!,\n ...(triggers.length === 0 ? {} : { triggers: [...triggers] }),\n ...(messages.length === 0 ? {} : { messages: messages.map((each) => ({ ...each })) }),\n ...(Object.keys(exitCodes).length === 0 ? {} : { exitCodes: { ...exitCodes } }),\n },\n };\n },\n start(options = {}) {\n // the start needs the whole graph: describe() is the check, and the runtime reads it\n if (runtime !== undefined) return runtime;\n if (running !== undefined) return Promise.reject(new Error(`${name} runs its lifecycle: use its health`));\n let made: Runtime;\n try {\n made = makeRuntime(options).runtime;\n } catch (error) {\n return Promise.reject(error);\n }\n started = true;\n live = made;\n runtime = made.warmUp().then(() => made);\n return runtime;\n },\n run(options = {}) {\n if (running !== undefined) return running;\n if (runtime !== undefined) return Promise.reject(new Error(`${name} started its health only: run() starts the whole lifecycle`));\n try {\n const description = builder.describe();\n const components: Components = {\n transports: transportImpls,\n dependencies: handles,\n healthServer: probes,\n phaseWork,\n choices,\n stopPollers: () => {},\n };\n const problems = lifecycleProblems(description, components);\n if (problems.length > 0) throw new Error(`${name}: ${problems.join(\"; \")}`);\n const made = makeRuntime(options);\n started = true;\n live = made.runtime;\n // the builder holds the lifecycle before the first transport starts\n const ran = lifecycle(made.description, made.runtime, { ...components, stopPollers: made.stopPollers }, options, (given) => {\n life = given;\n });\n running = ran.started.then(() => ran);\n } catch (error) {\n return Promise.reject(error);\n }\n return running;\n },\n };\n return builder;\n};\n","/**\n * This module is the evaluator of the timer-ordering law. Its decisions are the same as the\n * decisions of the research evaluator. The rules are data, and the caller gives them. Each rule\n * is one or more linear inequalities over symbols at a hop (`readiness_detection_window@pod`),\n * with a margin. A binding maps `symbol@hop` to seconds, or to \"inf\" for a timer that is absent.\n */\n\n/** A term is a coefficient times one symbol, at a hop when it has one. */\nexport interface Term {\n readonly knob: string;\n readonly coef: number;\n readonly at?: string | undefined;\n}\n\n/** A side is a sum of terms, plus a constant. */\nexport interface Side {\n readonly terms: readonly Term[];\n readonly const?: number | undefined;\n}\n\n/** An inequality compares two sides, with a margin. */\nexport interface Inequality {\n readonly lhs: Side;\n readonly op: \"<\" | \"<=\" | \">\" | \">=\";\n readonly rhs: Side;\n /** The margin is in seconds, or it is words for a margin that no binding gives (\"a factor of several\"). Words count as 0. */\n readonly margin?: number | string | undefined;\n}\n\n/** A rule is one or more inequalities, with their statement in words. */\nexport interface Rule {\n readonly id: string;\n /** This text is the rule in words. */\n readonly rule: string;\n /** This text is the window that a violation opens. */\n readonly window?: string | undefined;\n readonly expr: Inequality;\n readonly expr_more?: readonly Inequality[] | undefined;\n}\n\n/** A bound is in seconds, or it is \"inf\" for an absent timer, or \"off\" for a disabled feature. The last two have no limit. */\nexport type Bound = number | \"inf\" | \"off\";\n\n/**\n * A binding maps `symbol@hop` to its bound. Its \"margin\" replaces the margin of each inequality.\n * Its \"margins\" replace them one by one, in sequence, as the binding of a chain can.\n */\nexport type Binding = Readonly<Record<string, Bound | readonly number[] | undefined>> & {\n readonly margin?: number | undefined;\n readonly margins?: readonly number[] | undefined;\n};\n\n/** A verdict is \"holds\", \"violated\", \"unbounded\" (it holds only because a timer is absent) or \"depends\" (nothing is bound). */\nexport type Verdict = \"holds\" | \"violated\" | \"unbounded\" | \"depends\";\n\n/** An evaluation is the value of each side of one inequality, its margin, and if it holds. */\nexport interface Evaluated {\n readonly lhs: number | null;\n readonly rhs: number | null;\n readonly margin: number;\n readonly holds: boolean | null;\n}\n\nconst value = (bound: Bound): number =>\n bound === \"inf\" || bound === \"off\" ? Infinity : Number(bound);\nconst keyOf = (term: Term): string =>\n term.at !== undefined ? `${term.knob}@${term.at}` : term.knob;\n/** This function gives the bound of a symbol, or undefined when the symbol has no bound. */\nconst boundOf = (bind: Binding, key: string): Bound | undefined => {\n const bound = bind[key];\n return typeof bound === \"number\" || bound === \"inf\" || bound === \"off\" ? bound : undefined;\n};\n\n/** This function gives the inequalities of a rule: its expr, then the others. */\nexport const inequalities = (rule: Rule): readonly Inequality[] => [\n rule.expr,\n ...(rule.expr_more ?? []),\n];\n\n/** This function gives the symbols that a rule reads, as `symbol@hop`. */\nexport const symbolsOf = (rule: Rule): string[] => {\n const out: string[] = [];\n for (const inequality of inequalities(rule)) {\n for (const term of [...inequality.lhs.terms, ...inequality.rhs.terms]) {\n const key = keyOf(term);\n if (!out.includes(key)) out.push(key);\n }\n }\n return out;\n};\n\n/** This function gives the value of a side, Σ coef × symbol + const, or null when a symbol has no bound. */\nconst sideOf = (side: Side, bind: Binding): number | null => {\n let total = side.const ?? 0;\n for (const term of side.terms) {\n const bound = boundOf(bind, keyOf(term));\n if (bound === undefined) return null;\n total += term.coef * value(bound);\n }\n return total;\n};\n\n/** This function gives the margin of an inequality: from the binding (one for all, or one each), else from the rule, else 0. */\nconst marginOf = (inequality: Inequality, index: number, bind: Binding): number => {\n if (Array.isArray(bind.margins)) return Number(bind.margins[index] ?? 0);\n if (typeof bind.margin === \"number\") return bind.margin;\n return typeof inequality.margin === \"number\" ? inequality.margin : 0;\n};\n\n/**\n * This function evaluates each inequality on one binding. \"<\" holds when lhs + margin < rhs, and\n * \">\" holds when lhs > rhs + margin. Only the inequalities with all their symbols bound apply.\n * The others are null.\n */\nexport const evaluate = (rule: Rule, bind: Binding): Evaluated[] =>\n inequalities(rule).map((inequality, index) => {\n const lhs = sideOf(inequality.lhs, bind);\n const rhs = sideOf(inequality.rhs, bind);\n const margin = marginOf(inequality, index, bind);\n if (lhs === null || rhs === null) return { lhs, rhs, margin, holds: null };\n const holds =\n inequality.op === \"<\"\n ? lhs + margin < rhs\n : inequality.op === \"<=\"\n ? lhs + margin <= rhs\n : inequality.op === \">\"\n ? lhs > rhs + margin\n : lhs >= rhs + margin;\n return { lhs, rhs, margin, holds };\n });\n\n/**\n * This function gives the verdict of an evaluation. When an applicable inequality fails, the\n * verdict is \"violated\". When all hold only because a timer is absent, the verdict is \"unbounded\",\n * because nothing then limits the window. Otherwise the verdict is \"holds\". When no inequality\n * applies, the arithmetic cannot decide, and the verdict is \"depends\".\n */\nexport const verdictOf = (rule: Rule, bind: Binding, evaluated: readonly Evaluated[]): Verdict => {\n const applicable = evaluated.flatMap((entry, index) => (entry.holds === null ? [] : [index]));\n if (applicable.length === 0) return \"depends\";\n if (applicable.some((index) => evaluated[index]?.holds === false)) return \"violated\";\n const all = inequalities(rule);\n const infinite = applicable.some((index) => {\n const inequality = all[index]!;\n return [...inequality.lhs.terms, ...inequality.rhs.terms].some((term) => {\n const bound = boundOf(bind, keyOf(term));\n return bound !== undefined && value(bound) === Infinity;\n });\n });\n return infinite ? \"unbounded\" : \"holds\";\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { convertExact, convertible, rationals as r } from \"@mark1russell7/quantity\";\nimport type { Dependency, ServiceDescription, Transport } from \"./description.ts\";\nimport type { Binding, Bound, Evaluated, Rule, Verdict } from \"./law.ts\";\nimport { evaluate, symbolsOf, verdictOf } from \"./law.ts\";\nimport type { Limiter } from \"./limiter/policy.ts\";\nimport { idleSpan, longestRetryAfter, retryAfterSeconds } from \"./limiter/policy.ts\";\nimport { failSpan } from \"./timing.ts\";\n\n/**\n * This module applies the ordering law to a declaration. The declaration binds the symbols of the\n * service, from its primitives: the polls of its checks, the windows of its policies, its drain.\n * The scenario binds the symbols of the platform (preStop, grace, the probes of the kubelet,\n * propagation) and of each dependency (its failover time, the idle close of its server). Thus the\n * service gives the inequalities, and the scenario gives the values.\n *\n * A rule about a client applies one time for each dependency. A rule about a consumer applies one\n * time for each consumer and each worker. A rule about a limiter applies one time for each limiter.\n */\n\n/** A scenario gives the values of the platform and of each dependency, by the `symbol@hop` of the law. */\nexport interface Scenario {\n /** These are the values of the platform: prestop_sleep@pod, termination_grace@pod, probe_period@pod, propagation_bound@cluster. */\n readonly platform: Readonly<Record<string, Extent>>;\n /**\n * These are the probe windows of the kubelet, period × failure threshold. They add to the\n * windows of the declaration. A probe reads the cached verdict, thus detection is the latch,\n * then the probe.\n */\n readonly probes: { readonly readiness: Quantity; readonly liveness: Quantity };\n /** These are the values of each dependency, by its name: failover_time@dependency, server_idle_close@server. */\n readonly dependencies?: Readonly<Record<string, Readonly<Record<string, Extent>>>> | undefined;\n /** These are the values of the source of each consumer and worker, by its name and by the `symbol@hop` of the law: lease_duration@broker. */\n readonly transports?: Readonly<Record<string, Readonly<Record<string, Extent>>>> | undefined;\n /**\n * These are the values of the callers of each limiter, by its name and by the `symbol@hop` of the\n * law: client_retry_window@caller, retry_delay@caller. A symbol without a hop binds at `caller`.\n */\n readonly limiters?: Readonly<Record<string, Readonly<Record<string, Extent>>>> | undefined;\n}\n\n/** A finding is the verdict of one rule for one scope: the service, or the client of a dependency. */\nexport interface Finding {\n readonly rule: string;\n readonly scope: string;\n readonly verdict: Verdict;\n readonly statement: string;\n readonly window?: string | undefined;\n readonly evaluated: readonly Evaluated[];\n /** These are the symbols that have no bound. A \"depends\" verdict waits for them. */\n readonly unbound: readonly string[];\n}\n\n/** These are the identifiers of the rules that each declaration gets. */\nexport const SERVICE_RULES: readonly string[] = [\n \"O04\",\n \"O09\",\n \"O10\",\n \"O11\",\n \"O12\",\n \"O13\",\n \"O14\",\n \"O15\",\n \"O16\",\n \"O17\",\n \"O18\",\n \"O19\",\n \"O20\",\n \"O21\",\n \"O22\",\n \"O23\",\n \"O27\",\n \"O29\",\n \"O30\",\n];\n\n/**\n * These are the two rules of the law for a keyed limiter, as data. The caller of `lint()` gives\n * them, as it gives each other rule. Each one applies one time for each limiter.\n * - O29: the longest `Retry-After` of a limiter is at most the retry window of its caller. Its\n * second inequality applies the same bound to a new key at the cap of keys.\n * Otherwise the caller stops before the limit lets its call in, and a refusal becomes a failure.\n * - O30: the least delay of a caller before it sends a refused call again is at least the longest\n * `Retry-After` of the policy. Otherwise a caller that does not read the header sends again too\n * early, and the limiter refuses each early call again.\n *\n * The identifiers O29 and O30 are provisional. The corpus of the law in jarvis (R3, track B) has 28\n * rules, O01 to O28. It does not have these two rules yet, thus they take the next two identifiers.\n */\nexport const LIMITER_RULES: readonly Rule[] = [\n {\n id: \"O29\",\n rule: \"the longest Retry-After of a limiter, at its cap of keys too, is at most the retry window of its caller\",\n window: \"the caller stops before the limit lets its call in, thus a refusal becomes a failure\",\n expr: {\n lhs: { terms: [{ knob: \"retry_after\", coef: 1, at: \"limiter\" }] },\n op: \"<=\",\n rhs: { terms: [{ knob: \"client_retry_window\", coef: 1, at: \"caller\" }] },\n margin: 0,\n },\n expr_more: [\n {\n lhs: { terms: [{ knob: \"retry_after_at_cap\", coef: 1, at: \"limiter\" }] },\n op: \"<=\",\n rhs: { terms: [{ knob: \"client_retry_window\", coef: 1, at: \"caller\" }] },\n margin: 0,\n },\n ],\n },\n {\n id: \"O30\",\n rule: \"the least delay of a caller before it sends a refused call again is at least the longest Retry-After of the limiter\",\n window: \"a caller that does not read Retry-After sends again too early, and the limiter refuses each early call again\",\n expr: {\n lhs: { terms: [{ knob: \"retry_delay\", coef: 1, at: \"caller\" }] },\n op: \">=\",\n rhs: { terms: [{ knob: \"retry_after\", coef: 1, at: \"limiter\" }] },\n margin: 0,\n },\n },\n];\n\n/** This function gives a finite amount in seconds. */\nconst secondsOf = (amount: Quantity): number =>\n r.toNumber(convertExact(r.fromNumber(amount.value), amount.unit, \"s\"));\n/** This function gives an amount, or no bound, as the law binds it. */\nconst boundOf = (amount: Extent): Bound =>\n amount.value === \"infinite\" ? \"inf\" : secondsOf(amount);\n/** This function tells if a unit is a time. A unit that the package does not know is not a time. */\nconst isTime = (unit: string): boolean => {\n try {\n return convertible(unit, \"s\");\n } catch {\n return false;\n }\n};\n/** This function gives the largest of some numbers of seconds, or undefined when there are none. */\nconst most = (values: readonly number[]): number | undefined =>\n values.length === 0 ? undefined : Math.max(...values);\n\n/** This function gives what the declaration tells about the service, as symbols of the law, and the source of each. */\nexport const serviceBindings = (\n svc: ServiceDescription,\n scenario: Scenario,\n): { readonly bind: Record<string, Bound>; readonly from: Record<string, string> } => {\n const bind: Record<string, Bound> = {};\n const from: Record<string, string> = {};\n const set = (symbol: string, bound: Bound | undefined, said: string): void => {\n if (bound === undefined) return;\n bind[symbol] = bound;\n from[symbol] = said;\n };\n const gating = svc.checks.filter((check) => check.gates !== null);\n const readinessChecks = gating.filter((check) => check.gates === \"readiness\");\n const livenessChecks = gating.filter((check) => check.gates === \"liveness\");\n set(\n \"check_poll_interval@service\",\n most(gating.map((check) => secondsOf(check.poll.interval))),\n \"the slowest gating check's interval\",\n );\n set(\n \"check_timeout@service\",\n most(gating.map((check) => secondsOf(check.poll.timeout))),\n \"the longest gating check's timeout\",\n );\n set(\n \"slowest_poll@service\",\n most(\n gating.map(\n (check) =>\n secondsOf(check.poll.timeout) + secondsOf(check.poll.interval) * (1 + check.poll.jitter),\n ),\n ),\n \"a check's timeout plus one jittered interval, at its slowest\",\n );\n // the window of a policy is the time that its latch takes to fail when its slowest check times out\n const windowOf = (checks: typeof gating, policy: \"readiness\" | \"liveness\"): number | undefined =>\n most(\n checks.map((check) => secondsOf(failSpan(svc.policies[policy], check.poll, \"timeout\").max)),\n );\n const readiness = windowOf(readinessChecks, \"readiness\");\n const liveness = windowOf(livenessChecks, \"liveness\");\n set(\"readiness_detection_window@service\", readiness, \"the readiness latch, failing by timeout\");\n if (readiness !== undefined) {\n set(\n \"readiness_detection_window@pod\",\n readiness + secondsOf(scenario.probes.readiness),\n \"the readiness latch, then the kubelet's probe\",\n );\n }\n if (liveness !== undefined) {\n set(\n \"liveness_detection_window@pod\",\n liveness + secondsOf(scenario.probes.liveness),\n \"the liveness window, then the kubelet's probe\",\n );\n }\n set(\"startup_budget@pod\", secondsOf(svc.policies.startup), \"the declared startup budget\");\n set(\n \"process_drain_time@process\",\n svc.shutdown.phases.reduce((total, phase) => total + secondsOf(phase.cap), 0),\n `the shutdown phases' caps, summed (${svc.shutdown.phases.map((phase) => phase.name).join(\", \")})`,\n );\n set(\n \"cooperative_window@process\",\n boundOf(svc.shutdown.cooperativeWindow),\n \"the declared cooperative window\",\n );\n // the hold of \"fail readiness\" keeps the listener open after the signal, as a preStop sleep does\n const hold = svc.shutdown.phases.find((phase) => phase.name === \"fail readiness\");\n set(\n \"readiness_hold@process\",\n hold === undefined ? 0 : secondsOf(hold.cap),\n hold === undefined\n ? \"no fail readiness phase: the intake stops at once after the signal\"\n : \"the cap of the fail readiness phase, which holds while the endpoints update\",\n );\n for (const [symbol, amount] of Object.entries(scenario.platform))\n set(symbol, boundOf(amount), \"the scenario\");\n return { bind, from };\n};\n\n/** This function gives the client knobs of a dependency at @client, and the values of the scenario at its own hops. */\nconst dependencyBindings = (dependency: Dependency, scenario: Scenario): Record<string, Bound> => {\n const bind: Record<string, Bound> = {};\n for (const [knob, amount] of Object.entries(dependency.knobs))\n bind[`${knob}@client`] = boundOf(amount);\n for (const [symbol, amount] of Object.entries(scenario.dependencies?.[dependency.name] ?? {})) {\n bind[symbol.includes(\"@\") ? symbol : `${symbol}@dependency`] = boundOf(amount);\n }\n return bind;\n};\n\n/**\n * These are the hops of the law at which the knobs of a transport bind, by its kind. A worker does\n * its units as a consumer does, thus both bind at `consumer` (O20). A server binds at no hop yet.\n */\nconst TRANSPORT_HOPS: Readonly<Record<Transport[\"kind\"], string | null>> = { server: null, consumer: \"consumer\", worker: \"consumer\" };\n\n/**\n * This function gives the time knobs of a transport at the hop of its kind, and the values of the\n * scenario for its source. A knob with a hop in its name binds at that hop. A count binds no symbol.\n */\nconst transportBindings = (transport: Transport, hop: string, scenario: Scenario): Record<string, Bound> => {\n const bind: Record<string, Bound> = {};\n for (const [knob, amount] of Object.entries(transport.knobs)) {\n if (!isTime(amount.unit)) continue;\n bind[knob.includes(\"@\") ? knob : `${knob}@${hop}`] = boundOf(amount);\n }\n for (const [symbol, amount] of Object.entries(scenario.transports?.[transport.name] ?? {})) bind[symbol] = boundOf(amount);\n return bind;\n};\n\n/**\n * This function gives the symbols of a limiter, and the values of the scenario for its callers.\n * - `retry_after@limiter` is the longest `Retry-After` of a refusal by the policy, in whole seconds.\n * It is one interval of the bucket, or one window, as the HTTP edge sends it.\n * - `retry_after_at_cap@limiter` is the longest `Retry-After` of a new key at the cap of keys. It is\n * the idle span, `burst / rate` or one window.\n */\nconst limiterBindings = (limiter: Limiter, scenario: Scenario): Record<string, Bound> => {\n const bind: Record<string, Bound> = {\n \"retry_after@limiter\": retryAfterSeconds(longestRetryAfter(limiter.policy)),\n \"retry_after_at_cap@limiter\": retryAfterSeconds(idleSpan(limiter.policy)),\n };\n for (const [symbol, amount] of Object.entries(scenario.limiters?.[limiter.name] ?? {}))\n bind[symbol.includes(\"@\") ? symbol : `${symbol}@caller`] = boundOf(amount);\n return bind;\n};\n\nconst SCOPED = /@(client|dependency|server)$/;\nconst TRANSPORT_SCOPED = /@consumer$/;\nconst LIMITER_SCOPED = /@(limiter|caller)$/;\n\n/** This identifier is the rule of the findings about a field that the declaration does not give. */\nexport const DECLARATION_RULE = \"declaration\";\n\n/**\n * This function gives a finding for each field of the shutdown that a description does not give.\n * `describe()` refuses such a declaration. A description from another source, for example the\n * JSON of 0.4, can lack the field. The verdict is `depends`, and `unbound` names the field.\n */\nconst declarationFindings = (svc: ServiceDescription): Finding[] =>\n (svc.shutdown as { onRepeatSignal?: unknown }).onRepeatSignal === undefined\n ? [\n {\n rule: DECLARATION_RULE,\n scope: svc.name,\n verdict: \"depends\",\n statement: \"the declaration tells what a signal does while the shutdown runs: ignore or exit\",\n window: \"a repeat signal has no declared effect\",\n evaluated: [],\n unbound: [\"shutdown.onRepeatSignal\"],\n },\n ]\n : [];\n\n/**\n * This function applies each service rule to a declaration and a scenario. A rule applies one time\n * for the service, for each client, for each consumer and worker, or for each limiter. The function\n * also gives a finding for each necessary field that the description does not give (`DECLARATION_RULE`).\n */\nexport const lint = (\n svc: ServiceDescription,\n scenario: Scenario,\n rules: readonly Rule[],\n): Finding[] => {\n const service = serviceBindings(svc, scenario).bind;\n const findings: Finding[] = [...declarationFindings(svc)];\n for (const rule of rules) {\n if (!SERVICE_RULES.includes(rule.id)) continue;\n const symbols = symbolsOf(rule);\n const scopes: Array<[string, Binding]> = symbols.some((symbol) => LIMITER_SCOPED.test(symbol))\n ? (svc.limiters ?? []).map((limiter): [string, Binding] => [limiter.name, { ...service, ...limiterBindings(limiter, scenario) }])\n : symbols.some((symbol) => TRANSPORT_SCOPED.test(symbol))\n ? svc.transports.flatMap((transport): Array<[string, Binding]> => {\n const hop = TRANSPORT_HOPS[transport.kind];\n return hop === null ? [] : [[transport.name, { ...service, ...transportBindings(transport, hop, scenario) }]];\n })\n : symbols.some((symbol) => SCOPED.test(symbol))\n ? svc.dependencies.map((dependency) => [\n dependency.name,\n { ...service, ...dependencyBindings(dependency, scenario) },\n ])\n : [[svc.name, service]];\n for (const [scope, bind] of scopes) {\n const evaluated = evaluate(rule, bind);\n findings.push({\n rule: rule.id,\n scope,\n verdict: verdictOf(rule, bind, evaluated),\n statement: rule.rule,\n ...(rule.window !== undefined ? { window: rule.window } : {}),\n evaluated,\n unbound: symbols.filter((symbol) => bind[symbol] === undefined),\n });\n }\n }\n return findings;\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { convertible, valueIn } from \"@mark1russell7/quantity\";\nimport type { CooperativeFloor, Coupling, ExitCodes, MessageTrigger, Phase, RepeatSignal } from \"./description.ts\";\nimport type { ProcessTrigger } from \"./process.ts\";\nimport type { Timing } from \"./timing.ts\";\n\n/**\n * A profile is a part of a declaration as data: policies, phases and the rules of the shutdown.\n * `svc.profile(profile)` declares each field, as its method does. The runtime has no defaults, and\n * a profile is not a default, because the caller gives it. The caller can change each field with a\n * spread. `describe()` then shows the values of the profile.\n *\n * svc.profile({ ...kubernetes({ grace: s(60), preStop: s(5) }), onRepeatSignal: \"exit\" });\n */\nexport interface Profile {\n readonly readiness?: Timing | undefined;\n readonly liveness?: Timing | undefined;\n readonly startup?: Quantity | undefined;\n readonly couplings?: readonly Coupling[] | undefined;\n /** These are the phases of the shutdown, in their sequence. */\n readonly phases?: readonly Phase[] | undefined;\n readonly cooperativeWindow?: Extent | undefined;\n readonly cooperativeFloor?: CooperativeFloor | undefined;\n readonly onRepeatSignal?: RepeatSignal | undefined;\n readonly triggers?: readonly ProcessTrigger[] | undefined;\n /** These messages of the IPC channel start the shutdown, as `svc.trigger(\"ipc-message\", message)` declares each one. */\n readonly messages?: readonly MessageTrigger[] | undefined;\n readonly exitCodes?: ExitCodes | undefined;\n}\n\nconst s = (value: number): Quantity => ({ value, unit: \"s\" });\nconst phase = (name: string, cap: Quantity): Phase => ({ name, cap });\n\n/**\n * This profile is for a service on the computer of a developer. No load balancer routes to it,\n * thus it has no readiness hold. Its caps sum to 10 s, and a second signal exits at once. It\n * declares no checks, thus the caller declares readiness, liveness and the startup budget.\n */\nexport const localDev: Profile = {\n phases: [\n phase(\"stop intake\", s(1)),\n phase(\"drain\", s(4)),\n phase(\"close transports\", s(1)),\n phase(\"stop the poller\", s(1)),\n phase(\"tear down dependencies\", s(1)),\n phase(\"close the health server\", s(1)),\n phase(\"flush the output\", s(1)),\n ],\n cooperativeWindow: s(2),\n cooperativeFloor: \"half\",\n onRepeatSignal: \"exit\",\n};\n\n/**\n * This profile is for a background host on the computer of a developer, under a supervisor or a\n * command that stops it. It has the caps of `localDev`. A repeat signal has no effect, thus the\n * host ends its drain. It has no process trigger: a background host has no parent on stdin.\n */\nexport const daemon: Profile = {\n phases: localDev.phases!.map((each) => ({ ...each })),\n cooperativeWindow: localDev.cooperativeWindow!,\n cooperativeFloor: \"half\",\n onRepeatSignal: \"ignore\",\n};\n\n/**\n * This profile is for a small process: a command that runs one time, or a child process on stdio.\n * It has no checks and no probes, and its policies gate nothing. The cooperative abort occurs at the\n * start of the drain, thus a first Ctrl-C stops the work at once. A second signal exits at once.\n * The exit codes tell the shell how the process stopped: 130 for SIGINT, 143 for SIGTERM and 131\n * for SIGQUIT. A stdio child also declares `triggers: [\"stdin-close\"]`.\n */\nexport const ephemeral: Profile = {\n readiness: { type: \"window\", failAfter: s(0) },\n liveness: { type: \"window\", failAfter: s(0) },\n startup: s(10),\n phases: [\n phase(\"stop intake\", s(1)),\n phase(\"drain\", s(2)),\n phase(\"close transports\", s(1)),\n phase(\"stop the poller\", s(1)),\n phase(\"tear down dependencies\", s(2)),\n phase(\"flush the output\", s(1)),\n ],\n // the window is the whole drain, and no floor holds the abort back\n cooperativeWindow: s(2),\n cooperativeFloor: \"none\",\n onRepeatSignal: \"exit\",\n exitCodes: { SIGINT: 130, SIGTERM: 143, SIGQUIT: 131 },\n};\n\n/** These are the parts of the budget of each stage in the profile `kubernetes`, in thirtieths. */\nconst KUBERNETES_SHARES: ReadonlyArray<readonly [string, number]> = [\n [\"fail readiness\", 2],\n [\"stop intake\", 5],\n [\"drain\", 15],\n [\"close transports\", 2],\n [\"stop the poller\", 1],\n [\"tear down dependencies\", 2],\n [\"close the health server\", 1],\n];\n/** This part of the budget is the cooperative window, in thirtieths. */\nconst KUBERNETES_WINDOW = 5;\n\n/** These are the settings of a pod that the profile `kubernetes` derives its caps from. */\nexport interface PodTiming {\n /** This time is `terminationGracePeriodSeconds`: from the deletion of the pod to SIGKILL. */\n readonly grace: Quantity;\n /** This time is the preStop sleep, or 0 for no preStop hook. SIGTERM comes after it. */\n readonly preStop: Quantity;\n}\n\n/**\n * This function gives the profile of a pod in Kubernetes. The budget is the grace less the preStop\n * sleep: the time from SIGTERM to SIGKILL. Each stage gets a part of the budget, rounded down to\n * the millisecond.\n * - The parts in thirtieths are 2, 5, 15, 2, 1, 2 and 1, in the sequence of the stages. Thus 2\n * thirtieths of the budget stay as a margin before SIGKILL.\n * - The cooperative window is 5 thirtieths of the budget.\n * - The kubelet sends SIGTERM one time, thus a repeat signal has no effect.\n *\n * At the defaults of Kubernetes (a grace of 30 s and no preStop hook), the caps are 2, 5, 15, 2, 1,\n * 2 and 1 s. Thus the sum of the caps and the preStop sleep fits in the grace (O10). The window is\n * shorter than the drain, which is shorter than the budget (O16).\n */\nexport const kubernetes = (pod: PodTiming): Profile => {\n const time = (amount: Quantity, what: string): number => {\n if (!convertible(amount.unit, \"s\")) throw new Error(`the ${what} of the pod is not a time`);\n return valueIn(amount, \"ms\");\n };\n const grace = time(pod.grace, \"grace\");\n const preStop = time(pod.preStop, \"preStop sleep\");\n if (preStop < 0) throw new Error(\"the preStop sleep of the pod is less than 0\");\n const budget = grace - preStop;\n if (!(budget > 0)) throw new Error(`the grace of the pod (${grace} ms) is not longer than its preStop sleep (${preStop} ms)`);\n const part = (thirtieths: number): Quantity => s(Math.floor((budget * thirtieths) / 30) / 1000);\n return {\n phases: KUBERNETES_SHARES.map(([name, thirtieths]) => phase(name, part(thirtieths))),\n cooperativeWindow: part(KUBERNETES_WINDOW),\n cooperativeFloor: \"half\",\n onRepeatSignal: \"ignore\",\n };\n};\n","// The units of work of a worker loop and of a queue drain: the count of the units in flight, the\n// drain to a deadline with the cooperative abort, the sleeps on the clock, the bound of each unit,\n// and the request tracking of the service for each unit.\n\nimport { valueIn } from \"@mark1russell7/quantity\";\nimport type { Backoff } from \"./backoff.ts\";\nimport { backoffProblems } from \"./backoff.ts\";\nimport type { Cancel, Clock } from \"./clock.ts\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport type { KnobRecord } from \"./knobs.ts\";\nimport { boundedMillisecondsOf } from \"./knobs.ts\";\nimport type { Lifecycle } from \"./lifecycle.ts\";\nimport type { RequestEnd } from \"./requests.ts\";\n\n/**\n * A unit request names the route of each unit of work in the request tracking of the service. Then\n * the service admits, counts, drains and cuts each unit as it does each request (`life.request`).\n * The controller declares the route, thus its idempotency tells if a cut unit can go again.\n */\nexport interface UnitRequest<U> {\n /** This name is the controller that declares the route. */\n readonly controller: string;\n /** This name is the route of each unit, or a function that gives it from the unit. A route can match a route pattern. */\n readonly route: string | ((unit: U) => string);\n /** This function gives the detail of a unit, for the function of a route pattern. */\n readonly detail?: ((unit: U) => unknown) | undefined;\n}\n\n/**\n * A unit end tells how one unit of work ended:\n * - `done`: the work gave its value.\n * - `failed`: the work threw for a cause of its own, or after its bound aborted it.\n * - `refused`: the service did not admit the unit, thus the work did not start.\n * - `cut`: the shutdown stopped the unit. It is not a failure. `retryable` tells if the unit can go again.\n */\nexport type UnitEnd =\n | { readonly kind: \"done\"; readonly value: unknown }\n | { readonly kind: \"failed\"; readonly error: unknown }\n | { readonly kind: \"refused\"; readonly cause: string }\n | { readonly kind: \"cut\"; readonly cause: string; readonly retryable: boolean };\n\n/** This function gives the cause of an abort as text. */\nexport const causeOf = (signal: AbortSignal): string =>\n signal.reason instanceof Error ? signal.reason.message : String(signal.reason ?? \"the unit got an abort\");\n\n/** These are the parts of one unit of work. */\nexport interface UnitRun<U> {\n readonly clock: Clock;\n /** This time is the bound of the unit, in milliseconds, or infinity. At it, the signal of the work aborts. */\n readonly bound: number;\n /** This controller is the abort of the transport for the unit: the cooperative abort and the close. */\n readonly abort: AbortController;\n readonly life: Lifecycle;\n readonly request: UnitRequest<U> | undefined;\n readonly unit: U;\n /** This function starts the work, and gives its value or a promise. */\n readonly work: (signal: AbortSignal) => unknown;\n}\n\n/**\n * This function does one unit of work, and gives its end. With a request, the unit goes through\n * `life.request`, thus the service counts it, drains it and can cut it. A throw after the abort of\n * the transport is a cut, not a failure (S6 A10). A throw after the bound is a failure.\n */\nexport const runUnit = async <U>(run: UnitRun<U>): Promise<UnitEnd> => {\n const { clock, bound, abort, life, request, unit, work } = run;\n const timeout = new AbortController();\n const cancel: Cancel = Number.isFinite(bound)\n ? clock.after(bound, () => timeout.abort(new Error(`the unit did not end in its unit_processing_time of ${bound} ms`)))\n : () => {};\n const call = async (tracker?: AbortSignal): Promise<unknown> =>\n work(AbortSignal.any(tracker === undefined ? [abort.signal, timeout.signal] : [abort.signal, timeout.signal, tracker]));\n // the transport cannot read the idempotency of the route, thus a cut of its own does not go again\n const thrown = (error: unknown): UnitEnd => {\n if (abort.signal.aborted) return { kind: \"cut\", cause: causeOf(abort.signal), retryable: false };\n if (timeout.signal.aborted) return { kind: \"failed\", error: timeout.signal.reason };\n return { kind: \"failed\", error };\n };\n try {\n if (request === undefined) {\n try {\n return { kind: \"done\", value: await call() };\n } catch (error) {\n return thrown(error);\n }\n }\n let collected: Promise<{ readonly items: readonly unknown[]; readonly end: RequestEnd }>;\n try {\n const route = typeof request.route === \"string\" ? request.route : request.route(unit);\n const detail = request.detail?.(unit);\n // the value goes in a box: a work that gives an async iterable is one value here, not a stream\n const stream = life.request(request.controller, route, (signal) => call(signal).then((value) => ({ value })), detail === undefined ? {} : { detail });\n collected = stream.collect();\n } catch (error) {\n // an undeclared route, or a lifecycle with no service\n return { kind: \"failed\", error };\n }\n const { items, end } = await collected;\n if (end.kind === \"done\") return { kind: \"done\", value: (items[0] as { readonly value: unknown } | undefined)?.value };\n if (end.kind === \"failed\") return thrown(end.error);\n if (end.kind === \"refused\") return { kind: \"refused\", cause: end.cause };\n return { kind: \"cut\", cause: end.cause, retryable: end.retryable };\n } finally {\n cancel();\n }\n};\n\n/** A flight set counts the units in flight, from their events, and drains them to a deadline. */\nexport interface Flights {\n /** This count is the number of units in flight. */\n readonly size: number;\n /** This method adds a unit, and gives the function that removes it. A unit after the cooperative abort gets the abort at once. */\n add(unit: AbortController): () => void;\n /** This method aborts each unit in flight and each later unit: the cooperative abort, or the close. */\n abort(reason: unknown): void;\n /** This method removes each unit from the count: the close cuts them. */\n clear(): void;\n /** This method waits until no unit is in flight, or until the deadline. The signal is the cooperative abort. It does not throw. */\n drain(deadline: number, signal: AbortSignal): Promise<void>;\n /** This method gives a promise that ends when the count goes down, or at `release()`. */\n less(): Promise<void>;\n /** This method ends each promise of `less()`. */\n release(): void;\n}\n\n/** This function makes a flight set on a clock. */\nexport const flights = (clock: Clock): Flights => {\n const units = new Set<AbortController>();\n const idle = new Set<() => void>();\n const lower = new Set<() => void>();\n let aborted: { readonly reason: unknown } | null = null;\n const settle = (): void => {\n for (const done of [...lower]) done();\n lower.clear();\n if (units.size === 0) for (const done of [...idle]) done();\n };\n const abort = (reason: unknown): void => {\n aborted ??= { reason };\n for (const unit of [...units]) if (!unit.signal.aborted) unit.abort(aborted.reason);\n };\n return {\n get size() {\n return units.size;\n },\n add(unit) {\n units.add(unit);\n if (aborted !== null && !unit.signal.aborted) unit.abort(aborted.reason);\n return () => {\n if (units.delete(unit)) settle();\n };\n },\n abort,\n clear() {\n units.clear();\n settle();\n },\n drain(deadline, signal) {\n const cooperative = (): void => abort(signal.reason);\n if (signal.aborted) cooperative();\n else signal.addEventListener(\"abort\", cooperative, { once: true });\n // nothing in flight, or a deadline that passed: the drain ends at once, with no timer\n if (units.size === 0 || deadline <= clock.now()) {\n signal.removeEventListener(\"abort\", cooperative);\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n let cancel: Cancel = () => {};\n const done = (): void => {\n idle.delete(done);\n cancel();\n signal.removeEventListener(\"abort\", cooperative);\n resolve();\n };\n idle.add(done);\n cancel = clock.after(Math.max(0, deadline - clock.now()), done);\n });\n },\n less() {\n return new Promise<void>((resolve) => lower.add(resolve));\n },\n release() {\n for (const done of [...lower]) done();\n lower.clear();\n },\n };\n};\n\n/**\n * A sleeper gives the waits of a loop on the clock. `wake()` ends each wait that it can end, and\n * `stop()` ends each wait. A wait without a bound uses no timer.\n */\nexport interface Sleeper {\n /** This count goes up at each `wake()`. A loop reads it before a unit, and a wake during the unit then ends the next sleep at once. */\n readonly wakes: number;\n /** This method waits on the clock. A wake after `since` ends it, and with `since` past, it ends at once. */\n sleep(ms: number, since: number): Promise<void>;\n /** This method waits on the clock. A wake does not end it: it is a backoff after a failure. */\n backoff(ms: number): Promise<void>;\n /** This method ends each sleep, and gives the count of sleeps that it ended. */\n wake(): number;\n /** This method ends each wait, the backoffs too. Each later wait then ends at once. */\n stop(): void;\n}\n\n/** This function makes a sleeper on a clock. */\nexport const sleeper = (clock: Clock): Sleeper => {\n let wakes = 0;\n let stopped = false;\n const sleeps = new Set<() => void>();\n const backoffs = new Set<() => void>();\n const wait = (ms: number, into: Set<() => void>): Promise<void> =>\n stopped\n ? Promise.resolve()\n : new Promise<void>((resolve) => {\n let cancel: Cancel = () => {};\n const done = (): void => {\n if (!into.delete(done)) return;\n cancel();\n resolve();\n };\n into.add(done);\n if (Number.isFinite(ms)) cancel = clock.after(ms, done);\n });\n return {\n get wakes() {\n return wakes;\n },\n sleep(ms, since) {\n if (since !== wakes) return Promise.resolve();\n return wait(ms, sleeps);\n },\n backoff(ms) {\n return wait(ms, backoffs);\n },\n wake() {\n wakes += 1;\n const ended = sleeps.size;\n for (const done of [...sleeps]) done();\n return ended;\n },\n stop() {\n stopped = true;\n for (const done of [...sleeps, ...backoffs]) done();\n },\n };\n};\n\n/** A settled wait tells how a work ended in its bound: it ended, it threw, or the bound came first. */\nexport type Settled = { readonly kind: \"done\" } | { readonly kind: \"failed\"; readonly error: unknown } | { readonly kind: \"bound\" };\n\n/** This function waits for a work until a bound on the clock, in milliseconds. */\nexport const settleWithin = (clock: Clock, ms: number, work: Promise<unknown>): Promise<Settled> =>\n new Promise<Settled>((resolve) => {\n const cancel: Cancel = Number.isFinite(ms) ? clock.after(ms, () => resolve({ kind: \"bound\" })) : () => {};\n work.then(\n () => {\n cancel();\n resolve({ kind: \"done\" });\n },\n (error: unknown) => {\n cancel();\n resolve({ kind: \"failed\", error });\n },\n );\n });\n\n/**\n * This function gives the backoff of the knobs of a loop. The first delay is `retry_base`, and each\n * delay is two times longer, up to `retry_cap`. Each delay has a jitter up to the base, as in the Redis client.\n */\nexport const retryOf = (knobs: KnobRecord, owner: string): Backoff => {\n const base = boundedMillisecondsOf(knobs, \"retry_base\", owner);\n const cap = boundedMillisecondsOf(knobs, \"retry_cap\", owner);\n const backoff: Backoff = { base, factor: 2, cap, jitter: { kind: \"add\", amount: base } };\n const problems = backoffProblems(backoff);\n if (problems.length > 0) throw new Error(`${owner}: the retry_base and retry_cap give no backoff: ${problems.join(\", \")}`);\n return backoff;\n};\n\n/**\n * This function gives the problems of the bounds of a loop in a declaration. The close bound fits\n * in the cap of `close transports`. The bound of a unit fits in the cap of `drain`, or the drain can cut a unit (S6 A10).\n */\nexport const boundProblems = (owner: string, closeBound: number, unitBound: number, description: ServiceDescription): string[] => {\n const capOf = (name: string): number | undefined => {\n const phase = description.shutdown.phases.find((each) => each.name === name);\n return phase === undefined ? undefined : valueIn(phase.cap, \"ms\");\n };\n const found: string[] = [];\n const close = capOf(\"close transports\");\n if (close === undefined) found.push(`${owner} needs the phase \"close transports\" to close`);\n else if (closeBound >= close)\n found.push(`the close_bound of ${owner}, ${closeBound} ms, does not fit in the cap of \"close transports\", ${close} ms`);\n const drain = capOf(\"drain\");\n if (drain === undefined) found.push(`${owner} needs the phase \"drain\" to end its units`);\n else if (!Number.isFinite(unitBound))\n found.push(`the unit_processing_time of ${owner} has no bound, thus the drain can cut a unit at its cap of ${drain} ms`);\n else if (unitBound >= drain)\n found.push(`the unit_processing_time of ${owner}, ${unitBound} ms, does not fit in the cap of \"drain\", ${drain} ms`);\n return found;\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { backoffDelay } from \"./backoff.ts\";\nimport type { Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport { boundedMillisecondsOf, countOf, millisecondsOf } from \"./knobs.ts\";\nimport type { Lifecycle, TransportImpl } from \"./lifecycle.ts\";\nimport type { UnitRequest } from \"./units.ts\";\nimport { boundProblems, flights, retryOf, runUnit, settleWithin, sleeper } from \"./units.ts\";\n\n/**\n * These are the knobs of a worker loop, by the names of the ordering law where the law has them.\n * The loop has no defaults, thus each knob is necessary. A bound that nobody gives is \"infinite\".\n */\nexport interface WorkerKnobs {\n /**\n * This time is the sleep of a lane, from the end of one iteration to the start of the next. A\n * time without a bound starts the next iteration only at `wake()`.\n */\n readonly worker_sleep: Extent;\n /**\n * This time is the most that one iteration can take. At it, the loop aborts the signal of the\n * iteration, and a throw after it is a failure. The law reads it as `unit_processing_time@consumer` (O20).\n */\n readonly unit_processing_time: Extent;\n /** This time is the delay after the first failure in sequence. The delay is two times longer after each failure, with a jitter up to this time. */\n readonly retry_base: Quantity;\n /** This time is the most that one delay can be, before its jitter. */\n readonly retry_cap: Quantity;\n /** This time bounds the close: the end of the iterations after their abort, and then the teardown. */\n readonly close_bound: Quantity;\n /** This count (the unit `count`) is the number of lanes. Each lane does its iterations one at a time. */\n readonly concurrency: Quantity;\n /** The other knobs go to the declaration, for example `lease_duration@broker`. The loop does not read them. */\n readonly [knob: string]: Extent;\n}\n\n/** An iteration context is what the loop gives each iteration. */\nexport interface IterationContext<S> {\n /** This signal aborts at the cooperative abort of the drain, at the bound of the iteration, and at the close. */\n readonly signal: AbortSignal;\n /** This signal aborts when the intake stops. A long iteration can end at it in its own way. */\n readonly intake: AbortSignal;\n /** This value is the state that the setup gave, or undefined without a setup. */\n readonly state: S;\n /** This number is the lane of the iteration, from 0. */\n readonly lane: number;\n /** This count is the number of failures in sequence of the lane before this iteration. */\n readonly failures: number;\n /** This lifecycle is the lifecycle that the loop got at its start. */\n readonly life: Lifecycle;\n}\n\n/** These options make a worker loop. Each function can give a promise. */\nexport interface WorkerLoopOptions<S> {\n /** This function makes the state of the loop at its start, for example a connection. Its signal is the signal of the service. */\n readonly setup?: ((signal: AbortSignal) => S | PromiseLike<S>) | undefined;\n /**\n * This function does one iteration. When it gives `\"more\"`, the next iteration of its lane starts\n * after a zero sleep on the clock. A throw is a failure, and the lane then waits its backoff.\n */\n readonly iteration: (context: IterationContext<S>) => unknown;\n /** This function releases the state at the close. It occurs each time that the setup started, with undefined after a failed setup. */\n readonly teardown?: ((state: S | undefined) => void | PromiseLike<void>) | undefined;\n /** This clock is the clock of the lifecycle. The sleeps, the backoffs and the bounds use it. The default is `realClock`. */\n readonly clock?: Clock | undefined;\n /** This function gives the random numbers of the jitter, from 0 up to 1. The default is `Math.random`. */\n readonly random?: (() => number) | undefined;\n /**\n * This route puts each iteration through `life.request`: the service then admits it, counts it,\n * drains it and can cut it. The unit of a route function is the number of the lane.\n */\n readonly request?: UnitRequest<number> | undefined;\n /** This function receives each failure, with the count of failures in sequence of its lane. A refusal of the service is a failure too. */\n readonly onError?: ((error: unknown, failures: number) => void) | undefined;\n}\n\n/** A worker loop is a transport of the lifecycle whose work is a loop of iterations (S6 A10). */\nexport interface WorkerLoop extends TransportImpl {\n /** These knobs go to the declaration of the worker: `svc.worker(name, loop.knobs, loop)`. */\n readonly knobs: WorkerKnobs;\n /**\n * This method ends the sleep of each lane at once, for example when new work is ready. It does\n * not end a backoff. It gives false after the intake stops.\n */\n wake(): boolean;\n /** This method gives the problems of the knobs in a declaration: the close bound and the bound of an iteration against the caps. */\n problems(description: ServiceDescription): string[];\n}\n\nconst OWNER = \"workerLoop\";\n\n/**\n * This function makes a worker loop as a transport (S6 A10). It has a setup, an iteration and a\n * teardown, and each lane does its iterations one at a time.\n * - The start does the setup. A failed setup gets its teardown, and the start throws.\n * - The first iteration of each lane comes after the startup ends. Each sleep and each backoff is on the clock.\n * - `stopIntake` starts no new iteration, and it ends each sleep and each backoff.\n * - `drain` waits for each iteration in flight until the deadline, and gives it the cooperative\n * abort. A throw after that abort is not a failure.\n * - `close` aborts each iteration, waits for its end, and does the teardown, all in `close_bound`.\n */\nexport const workerLoop = <S = undefined>(knobs: WorkerKnobs, options: WorkerLoopOptions<S>): WorkerLoop => {\n const sleep = millisecondsOf(knobs, \"worker_sleep\", OWNER);\n const bound = millisecondsOf(knobs, \"unit_processing_time\", OWNER);\n const backoff = retryOf(knobs, OWNER);\n const closeBound = boundedMillisecondsOf(knobs, \"close_bound\", OWNER);\n const lanes = countOf(knobs, \"concurrency\", OWNER);\n if (!Number.isFinite(lanes)) throw new Error(`${OWNER} needs a concurrency with a bound: each lane is a loop`);\n const clock = options.clock ?? realClock;\n const random = options.random ?? Math.random;\n const running = flights(clock);\n const rests = sleeper(clock);\n const intake = new AbortController();\n // the work of each iteration until it ends, also after a cut: the teardown waits for it\n const pending = new Set<Promise<unknown>>();\n let started = false;\n let setup: Promise<S | undefined> | null = null;\n let state: S | undefined;\n let tornDown: Promise<void> | null = null;\n let closing: Promise<void> | null = null;\n\n const report = (error: unknown, failures: number): void => {\n try {\n options.onError?.(error, failures);\n } catch {\n // an error of the hook does not stop the loop\n }\n };\n /** This function does the teardown one time, after the setup ends, and only when the setup started. */\n const teardown = (): Promise<void> => {\n if (tornDown !== null) return tornDown;\n const release = options.teardown;\n const made = setup;\n tornDown =\n made === null || release === undefined\n ? Promise.resolve()\n : made.then(\n (given) => release(given),\n () => release(undefined),\n );\n return tornDown;\n };\n const keep = (work: Promise<unknown>): Promise<unknown> => {\n pending.add(work);\n const forget = (): void => {\n pending.delete(work);\n };\n work.then(forget, forget);\n return work;\n };\n\n /** This function is one lane: an iteration, then its sleep or its backoff, until the intake stops. */\n const lane = async (index: number, life: Lifecycle): Promise<void> => {\n let failures = 0;\n let since = rests.wakes;\n // the first iteration comes after a zero sleep on the clock: a wake starts it at once\n await rests.sleep(0, since);\n for (;;) {\n if (intake.signal.aborted) return;\n since = rests.wakes;\n const abort = new AbortController();\n const remove = running.add(abort);\n const count = failures;\n const end = await runUnit({\n clock,\n bound,\n abort,\n life,\n request: options.request,\n unit: index,\n work: (signal) =>\n keep(\n (async () =>\n options.iteration({ signal, intake: intake.signal, state: state as S, lane: index, failures: count, life }))(),\n ),\n });\n remove();\n // the shutdown cut the iteration: that is not a failure, and the lane ends (A10)\n if (end.kind === \"cut\") return;\n if (end.kind === \"done\") {\n failures = 0;\n await rests.sleep(end.value === \"more\" ? 0 : sleep, end.value === \"more\" ? rests.wakes : since);\n continue;\n }\n failures += 1;\n report(end.kind === \"failed\" ? end.error : new Error(`the service refused the iteration: ${end.cause}`), failures);\n await rests.backoff(backoffDelay(backoff, failures, random));\n }\n };\n\n return {\n knobs: { ...knobs },\n async start(signal, life) {\n if (closing !== null) throw new Error(`${OWNER}: a closed loop does not start again`);\n if (started) throw new Error(`${OWNER}: the loop started already`);\n started = true;\n const make = options.setup;\n // without a setup function, the setup is empty, and the teardown still occurs at the close\n setup = make === undefined ? Promise.resolve(undefined) : new Promise<S>((resolve) => resolve(make(signal)));\n try {\n await setup.then((given) => {\n state = given;\n });\n } catch (error) {\n // the lifecycle does not close a part that did not start, thus the teardown occurs here (A10)\n await settleWithin(clock, closeBound, teardown());\n throw error;\n }\n // the first iterations wait for the end of the startup, because a request before it gets a refusal\n void life.started.then(() => {\n if (intake.signal.aborted || life.state !== \"running\") return;\n // a lane catches each failure of its work: a rejection here is a defect, and it does not end the process (A5)\n for (let index = 0; index < lanes; index += 1) lane(index, life).catch((error: unknown) => report(error, 0));\n });\n },\n stopIntake() {\n if (intake.signal.aborted) return;\n intake.abort(new Error(`${OWNER} stopped its intake`));\n rests.stop();\n },\n drain(deadline, signal) {\n return running.drain(deadline, signal);\n },\n inFlight: () => running.size,\n wake() {\n if (intake.signal.aborted) return false;\n rests.wake();\n return true;\n },\n close() {\n if (closing !== null) return closing;\n if (!intake.signal.aborted) intake.abort(new Error(`${OWNER} closed`));\n rests.stop();\n running.abort(new Error(`${OWNER} closed`));\n running.clear();\n closing = (async () => {\n const began = clock.now();\n const ended = await settleWithin(clock, closeBound, Promise.allSettled([...pending]));\n // the teardown occurs also after an iteration that did not end, because the setup started (A10)\n const down = await settleWithin(clock, Math.max(0, closeBound - (clock.now() - began)), teardown());\n if (ended.kind === \"bound\")\n throw new Error(`${OWNER}: an iteration did not end in the close_bound of ${closeBound} ms after its abort`);\n if (down.kind === \"failed\") throw down.error;\n if (down.kind === \"bound\") throw new Error(`${OWNER}: the teardown did not end in the close_bound of ${closeBound} ms`);\n })();\n return closing;\n },\n problems(description) {\n return boundProblems(OWNER, closeBound, bound, description);\n },\n };\n};\n","import type { Extent, Quantity } from \"@mark1russell7/quantity\";\nimport { backoffDelay } from \"./backoff.ts\";\nimport type { Clock } from \"./clock.ts\";\nimport { realClock } from \"./clock.ts\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport { boundedMillisecondsOf, countOf, millisecondsOf } from \"./knobs.ts\";\nimport type { Lifecycle, TransportImpl } from \"./lifecycle.ts\";\nimport type { UnitEnd, UnitRequest } from \"./units.ts\";\nimport { boundProblems, flights, retryOf, runUnit, settleWithin, sleeper } from \"./units.ts\";\n\n/**\n * These are the knobs of a queue drain, by the names of the ordering law where the law has them.\n * The drain has no defaults, thus each knob is necessary. A bound that nobody gives is \"infinite\".\n */\nexport interface QueueKnobs {\n /** This time is the wait after a take that gives no job, before the next take. A time without a bound waits for `wake()`. */\n readonly queue_poll_interval: Extent;\n /**\n * This time is the most that one job can take. At it, the drain aborts the signal of the job, and\n * a throw after it is a failure. The law reads it as `unit_processing_time@consumer` (O20).\n */\n readonly unit_processing_time: Extent;\n /** This time is the delay after the first failed take in sequence, or after a refusal of the service. The delay is two times longer after each one. */\n readonly retry_base: Quantity;\n /** This time is the most that one delay can be, before its jitter. */\n readonly retry_cap: Quantity;\n /** This time bounds the close: the end of the jobs after their abort, and then the close of the source. */\n readonly close_bound: Quantity;\n /** This count (the unit `count`) is the most jobs in flight at one time. A count without a bound takes each job that comes. */\n readonly concurrency: Extent;\n /** The other knobs go to the declaration, for example `lease_duration@broker`. The drain does not read them. */\n readonly [knob: string]: Extent;\n}\n\n/**\n * A job source gives the jobs of a queue drain:\n * - A function takes the next job, or gives null when no job is ready. Its signal aborts when the intake stops.\n * - An async iterable gives the jobs in sequence. The drain asks for the next job only when it has a free slot.\n * At the stop of the intake, the drain ends the iterator through `return()`.\n */\nexport type JobSource<J> = ((signal: AbortSignal) => J | null | undefined | PromiseLike<J | null | undefined>) | AsyncIterable<J>;\n\n/**\n * A job action is what the drain does with a job that failed:\n * - `requeue`: the job goes back on the queue.\n * - `reject`: the job leaves the queue without a success, for example to the dead-letter route of the queue.\n * - `ack`: the job leaves the queue, as a poison message does.\n */\nexport type JobAction = \"requeue\" | \"reject\" | \"ack\";\n\n/** A job failure is a job whose handler failed, with the count of its deliveries, 1 at the first. */\nexport interface JobFailure<J> {\n readonly job: J;\n readonly error: unknown;\n readonly delivery: number;\n}\n\n/** A redelivery policy gives the action for a job that failed. The queue declares it, and it has no default (S6 A11). */\nexport type RedeliveryPolicy<J> = (failure: JobFailure<J>) => JobAction;\n\n/**\n * A requeue cause tells why a job goes back on the queue:\n * - `failed`: the redelivery policy sent it back after a failure.\n * - `unstarted`: the drain took the job and did not start it, because its intake stopped or the service refused it.\n * - `cut`: the shutdown cut the job, and its route declares that it can go again.\n */\nexport type RequeueCause = \"failed\" | \"unstarted\" | \"cut\";\n\n/** A job settle is how the drain tells the queue the end of each job. Each function can give a promise. */\nexport interface JobSettle<J> {\n /** This function removes the job from the queue: a success, or the action `ack`. */\n ack(job: J): void | PromiseLike<void>;\n /** This function puts the job back on the queue, or hands it back to the queue at the stop. */\n requeue(job: J, cause: RequeueCause): void | PromiseLike<void>;\n /** This function removes the job from the queue without a success: the action `reject`, or a cut job that cannot go again. */\n reject(job: J, error: unknown): void | PromiseLike<void>;\n /**\n * This function gives the count of deliveries of a job from the queue, 1 at the first. The queue\n * knows it, for example `x-delivery-count` of RabbitMQ or `ApproximateReceiveCount` of SQS. A\n * queue in memory counts for itself. The drain has no default, because a broker gives a new object at each delivery.\n */\n delivery(job: J): number;\n}\n\n/** A job context is what the drain gives the handler of each job. */\nexport interface JobContext {\n /** This signal aborts at the cooperative abort of the drain, at the bound of the job, and at the close. */\n readonly signal: AbortSignal;\n /** This signal aborts when the intake stops. */\n readonly intake: AbortSignal;\n /** This count is the delivery of the job, 1 at the first. */\n readonly delivery: number;\n /** This lifecycle is the lifecycle that the drain got at its start. */\n readonly life: Lifecycle;\n}\n\n/** These options make a queue drain. Each function can give a promise. */\nexport interface QueueDrainOptions<J> {\n readonly source: JobSource<J>;\n /** This function does one job. A throw is a failure, and the redelivery policy then gives its action. */\n readonly handle: (job: J, context: JobContext) => unknown;\n readonly settle: JobSettle<J>;\n /** This policy gives the action for each failed job. `redeliverOnce` gives the policy of S6 A11. */\n readonly redelivery: RedeliveryPolicy<J>;\n /** This function closes the source at the close, after the jobs end: for example, it closes a channel. */\n readonly close?: (() => void | PromiseLike<void>) | undefined;\n /** This clock is the clock of the lifecycle. The polls, the backoffs and the bounds use it. The default is `realClock`. */\n readonly clock?: Clock | undefined;\n /** This function gives the random numbers of the jitter, from 0 up to 1. The default is `Math.random`. */\n readonly random?: (() => number) | undefined;\n /**\n * This route puts each job through `life.request`: the service then admits it, counts it, drains\n * it and can cut it. The idempotency of the route tells if a cut job goes back on the queue.\n */\n readonly request?: UnitRequest<J> | undefined;\n /**\n * This function receives each failure: of a take, of a job, of a settle and of a policy. It also\n * receives the end of a source while the intake is open. The job is undefined for a take and for that end.\n */\n readonly onError?: ((error: unknown, job: J | undefined) => void) | undefined;\n}\n\n/** A queue drain is a transport of the lifecycle whose work is the jobs of a queue (S6 A11). */\nexport interface QueueDrain extends TransportImpl {\n /** These knobs go to the declaration of the consumer: `svc.consumer(name, drain.knobs, drain)`. */\n readonly knobs: QueueKnobs;\n /** This method ends the wait of a poll at once, for example when a job comes. It gives false after the intake stops. */\n wake(): boolean;\n /** This method gives the problems of the knobs in a declaration: the close bound and the bound of a job against the caps. */\n problems(description: ServiceDescription): string[];\n}\n\n/**\n * This function gives the redelivery policy of S6 A11. A poison message gets `ack`. Each other job\n * goes back on the queue after its first failure, one time. After a later failure, `then` gives the\n * action: the declared policy of the queue.\n */\nexport const redeliverOnce =\n <J>(then: JobAction | RedeliveryPolicy<J>, poison?: (error: unknown, job: J) => boolean): RedeliveryPolicy<J> =>\n (failure) => {\n if (poison?.(failure.error, failure.job) === true) return \"ack\";\n if (failure.delivery <= 1) return \"requeue\";\n return typeof then === \"function\" ? then(failure) : then;\n };\n\nconst OWNER = \"queueDrain\";\nconst ACTIONS: readonly string[] = [\"requeue\", \"reject\", \"ack\"];\nconst STOPPED: unique symbol = Symbol(\"the intake stopped\");\n\ntype Taken<J> = { readonly kind: \"job\"; readonly job: J } | { readonly kind: \"none\" } | { readonly kind: \"end\" } | { readonly kind: \"error\"; readonly error: unknown };\n\ninterface Active<J> {\n readonly job: J;\n settled: boolean;\n}\n\nconst isAsyncIterable = (value: unknown): value is AsyncIterable<unknown> =>\n value !== null &&\n (typeof value === \"object\" || typeof value === \"function\") &&\n typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === \"function\";\n\n/**\n * This function makes a queue drain as a transport (S6 A11). One taker takes the jobs from the\n * source while a slot is free, and each job operates in its slot.\n * - A success gets `ack`. A failure gets the action of the redelivery policy.\n * - `stopIntake` takes no new job, and a job that the drain took and did not start goes back (`requeue`, `unstarted`).\n * - `drain` waits for each job in flight until the deadline, and gives it the cooperative abort.\n * - `close` aborts each job, waits for its end, and closes the source, all in `close_bound`. A job\n * that does not end in the bound gets `reject`.\n */\nexport const queueDrain = <J>(knobs: QueueKnobs, options: QueueDrainOptions<J>): QueueDrain => {\n const poll = millisecondsOf(knobs, \"queue_poll_interval\", OWNER);\n const bound = millisecondsOf(knobs, \"unit_processing_time\", OWNER);\n const backoff = retryOf(knobs, OWNER);\n const closeBound = boundedMillisecondsOf(knobs, \"close_bound\", OWNER);\n const concurrency = countOf(knobs, \"concurrency\", OWNER);\n const { settle } = options;\n const clock = options.clock ?? realClock;\n const random = options.random ?? Math.random;\n const running = flights(clock);\n const rests = sleeper(clock);\n const intake = new AbortController();\n const stopped = new Promise<typeof STOPPED>((resolve) =>\n intake.signal.addEventListener(\"abort\", () => resolve(STOPPED), { once: true }),\n );\n // each job until its settle ends, and each job that goes back: the close waits for them\n const pending = new Set<Promise<unknown>>();\n const active = new Set<Active<J>>();\n let refusals = 0;\n let pausedUntil = Number.NEGATIVE_INFINITY;\n let cancelSource: () => void = () => {};\n let started = false;\n let closing: Promise<void> | null = null;\n\n const report = (error: unknown, job: J | undefined): void => {\n try {\n options.onError?.(error, job);\n } catch {\n // an error of the hook does not stop the drain\n }\n };\n const keep = (work: Promise<unknown>): void => {\n pending.add(work);\n const forget = (): void => {\n pending.delete(work);\n };\n work.then(forget, forget);\n };\n /** This function tells the queue the end of a job, one time. A throw of the queue is a failure. */\n const once = async (unit: Active<J>, tell: () => void | PromiseLike<void>): Promise<void> => {\n if (unit.settled) return;\n unit.settled = true;\n try {\n await tell();\n } catch (error) {\n report(error, unit.job);\n }\n };\n const handBack = (job: J): void =>\n keep(\n (async () => {\n try {\n await settle.requeue(job, \"unstarted\");\n } catch (error) {\n report(error, job);\n }\n })(),\n );\n\n /** This function gives the action of the policy for a failed job. A policy that throws, or that gives no action, rejects the job. */\n const actionOf = (job: J, error: unknown, delivery: number): JobAction => {\n try {\n const action = options.redelivery({ job, error, delivery });\n if (ACTIONS.includes(action)) return action;\n report(new Error(`the redelivery policy gave ${String(action)}, not requeue, reject or ack`), job);\n } catch (thrown) {\n report(thrown, job);\n }\n return \"reject\";\n };\n\n const settleEnd = (unit: Active<J>, end: UnitEnd, delivery: number): Promise<void> => {\n const { job } = unit;\n if (end.kind === \"done\") return once(unit, () => settle.ack(job));\n if (end.kind === \"refused\") {\n report(new Error(`the service refused the job: ${end.cause}`), job);\n return once(unit, () => settle.requeue(job, \"unstarted\"));\n }\n if (end.kind === \"cut\") {\n // a cut is not a failure. Only a route that can go again puts the job back (S6 A12)\n if (end.retryable) return once(unit, () => settle.requeue(job, \"cut\"));\n const cut = new Error(end.cause);\n return once(unit, () => settle.reject(job, cut));\n }\n const { error } = end;\n report(error, job);\n const action = actionOf(job, error, delivery);\n if (action === \"requeue\") return once(unit, () => settle.requeue(job, \"failed\"));\n return once(unit, () => (action === \"ack\" ? settle.ack(job) : settle.reject(job, error)));\n };\n\n /** This function starts one job in a slot. The slot stays in flight until the queue has the end of the job. */\n const runJob = (job: J, life: Lifecycle): void => {\n const unit: Active<J> = { job, settled: false };\n active.add(unit);\n const abort = new AbortController();\n const remove = running.add(abort);\n let delivery: number;\n try {\n delivery = settle.delivery(job);\n } catch (error) {\n // a count that the queue cannot give is not a first delivery: the job does not go back for free\n report(error, job);\n delivery = Number.POSITIVE_INFINITY;\n }\n keep(\n (async () => {\n const end = await runUnit({\n clock,\n bound,\n abort,\n life,\n request: options.request,\n unit: job,\n work: (signal) => options.handle(job, { signal, intake: intake.signal, delivery, life }),\n });\n // a refusal of the service stops the takes for a backoff, thus a controller that is not ready does not get each job\n if (end.kind === \"refused\") {\n refusals += 1;\n pausedUntil = clock.now() + backoffDelay(backoff, refusals, random);\n } else refusals = 0;\n await settleEnd(unit, end, delivery);\n })().finally(() => {\n active.delete(unit);\n remove();\n }),\n );\n };\n\n /** This function gives the take of the source. */\n const takeOf = (): (() => Promise<Taken<J>>) => {\n const source = options.source;\n if (isAsyncIterable(source)) {\n const iterator = (source as AsyncIterable<J>)[Symbol.asyncIterator]();\n cancelSource = () => {\n try {\n void Promise.resolve(iterator.return?.()).catch(() => {});\n } catch {\n // an iterator whose return() throws has ended\n }\n };\n return async () => {\n const step = await iterator.next();\n return step.done === true ? { kind: \"end\" } : { kind: \"job\", job: step.value };\n };\n }\n const pull = source as (signal: AbortSignal) => J | null | undefined | PromiseLike<J | null | undefined>;\n return () =>\n new Promise<J | null | undefined>((resolve) => resolve(pull(intake.signal))).then(\n (job): Taken<J> => (job === null || job === undefined ? { kind: \"none\" } : { kind: \"job\", job }),\n );\n };\n\n /** This function is the taker: it takes a job while a slot is free, until the intake stops or the source ends. */\n const taker = async (life: Lifecycle): Promise<void> => {\n const take = takeOf();\n let failures = 0;\n for (;;) {\n if (intake.signal.aborted) return;\n if (running.size >= concurrency) {\n await running.less();\n continue;\n }\n const pause = pausedUntil - clock.now();\n if (pause > 0) {\n await rests.backoff(pause);\n continue;\n }\n const since = rests.wakes;\n const taking = take().catch((error: unknown): Taken<J> => ({ kind: \"error\", error }));\n const first = await Promise.race([taking, stopped]);\n if (first === STOPPED || intake.signal.aborted) {\n // a take that ends after the stop gives a job that the drain does not start: it goes back\n if (first === STOPPED)\n void taking.then((late) => {\n if (late.kind === \"job\") handBack(late.job);\n });\n else if (first.kind === \"job\") handBack(first.job);\n return;\n }\n if (first.kind === \"error\") {\n failures += 1;\n report(first.error, undefined);\n await rests.backoff(backoffDelay(backoff, failures, random));\n continue;\n }\n failures = 0;\n if (first.kind === \"end\") {\n // the source ended while the intake is open: the drain takes no more jobs, thus it says so\n report(new Error(`the source of ${OWNER} ended while its intake was open: it takes no more jobs`), undefined);\n return;\n }\n if (first.kind === \"none\") {\n await rests.sleep(poll, since);\n continue;\n }\n runJob(first.job, life);\n }\n };\n\n const stopTaking = (cause: string): void => {\n if (intake.signal.aborted) return;\n intake.abort(new Error(cause));\n rests.stop();\n running.release();\n cancelSource();\n };\n\n return {\n knobs: { ...knobs },\n start(_signal, life) {\n if (closing !== null) throw new Error(`${OWNER}: a closed drain does not start again`);\n if (started) throw new Error(`${OWNER}: the drain started already`);\n started = true;\n // the first take waits for the end of the startup, because a request before it gets a refusal\n void life.started.then(() => {\n if (intake.signal.aborted || life.state !== \"running\") return;\n // the taker catches each failure of the source: a rejection here is a defect, and it does not end the process (A5)\n taker(life).catch((error: unknown) => report(error, undefined));\n });\n },\n stopIntake() {\n stopTaking(`${OWNER} stopped its intake`);\n },\n drain(deadline, signal) {\n return running.drain(deadline, signal);\n },\n inFlight: () => running.size,\n wake() {\n if (intake.signal.aborted) return false;\n rests.wake();\n return true;\n },\n close() {\n if (closing !== null) return closing;\n stopTaking(`${OWNER} closed`);\n running.abort(new Error(`${OWNER} closed`));\n running.clear();\n closing = (async () => {\n const began = clock.now();\n const ended = await settleWithin(clock, closeBound, Promise.allSettled([...pending]));\n if (ended.kind === \"bound\")\n for (const unit of [...active])\n void once(unit, () => settle.reject(unit.job, new Error(`${OWNER} closed with the job in flight`)));\n const shut = options.close;\n const down = await settleWithin(\n clock,\n Math.max(0, closeBound - (clock.now() - began)),\n shut === undefined ? Promise.resolve() : (async () => shut())(),\n );\n if (ended.kind === \"bound\") throw new Error(`${OWNER}: a job did not end in the close_bound of ${closeBound} ms after its abort`);\n if (down.kind === \"failed\") throw down.error;\n if (down.kind === \"bound\") throw new Error(`${OWNER}: the close of the source did not end in the close_bound of ${closeBound} ms`);\n })();\n return closing;\n },\n problems(description) {\n return boundProblems(OWNER, closeBound, bound, description);\n },\n };\n};\n","import type { Machine, TransitionDef } from \"@mark1russell7/algebra\";\nimport type { ServiceDescription } from \"./description.ts\";\nimport type { MachineName } from \"./events.ts\";\n\n/**\n * The machines of the runtime as `mark1russell7.machine/1` documents. The documents are the\n * specification, and TypeScript implements them. A test records the transitions of the runtime\n * and replays them against each document (`replay` of `@mark1russell7/algebra`), thus the code and\n * the documents cannot disagree.\n */\n\nconst SOURCE = [{ ref: \"packages/service/src (the runtime implements this document)\", rung: \"implemented\" as const }];\nconst base = (id: string, title: string): Pick<Machine, \"format\" | \"id\" | \"title\" | \"layer\" | \"version\" | \"sources\"> => ({\n format: \"mark1russell7.machine/1\",\n id: `service.machine.${id}`,\n title,\n layer: \"self\",\n version: \"0.2.0\",\n sources: SOURCE,\n});\nconst t = (\n id: string,\n from: string | readonly string[],\n on: string | readonly string[],\n to: string,\n extra: Partial<TransitionDef> = {},\n): TransitionDef => ({ id, from, on, to, ...extra });\n\n/**\n * The startup gate opens one time. The lifecycle moves it from `closed` to `starting` while its\n * components start. Then one warm-up sweep of each check opens it. A component that does not start\n * fails it for good.\n */\nexport const GATE_MACHINE: Machine = {\n ...base(\"gate\", \"The startup gate\"),\n states: {\n closed: { initial: true },\n starting: { note: \"the health server, then the dependencies, then the transports\" },\n sweeping: { note: \"one bounded warm-up sweep of each check\" },\n open: { final: true },\n failed: { final: true },\n },\n events: {\n \"startup.begin\": { kind: \"local\" },\n \"component.started\": { kind: \"local\" },\n \"mark-ready\": { kind: \"local\" },\n \"sweep.done\": { kind: \"local\" },\n \"startup.fail\": { kind: \"local\" },\n \"startup.over-budget\": { kind: \"timer\" },\n },\n knobs: { startup: { key: \"policies.startup\", scope: \"service\", unit: \"s\", default: null } },\n timers: {\n startup_budget: {\n duration: { knob: \"startup\", unit: \"s\" },\n arms: [\"enter:closed\"],\n cancels: [\"sweep.done\", \"startup.fail\"],\n fires: \"startup.over-budget\",\n note: \"the gate says that it is over its budget, and the startup probe of the platform acts on it\",\n },\n },\n transitions: [\n t(\"begin\", \"closed\", \"startup.begin\", \"starting\"),\n t(\"component\", \"starting\", \"component.started\", \"starting\"),\n t(\"mark-ready\", [\"closed\", \"starting\"], \"mark-ready\", \"sweeping\"),\n t(\"open\", \"sweeping\", \"sweep.done\", \"open\"),\n t(\"fail\", [\"closed\", \"starting\", \"sweeping\"], \"startup.fail\", \"failed\"),\n // the budget timer leaves each state where it is\n t(\"over-budget-closed\", \"closed\", \"startup.over-budget\", \"closed\", { timer: \"startup_budget\" }),\n t(\"over-budget-starting\", \"starting\", \"startup.over-budget\", \"starting\", { timer: \"startup_budget\" }),\n t(\"over-budget-sweeping\", \"sweeping\", \"startup.over-budget\", \"sweeping\", { timer: \"startup_budget\" }),\n ],\n};\n\n/** A debounce latch counts the polls of its check in sequence. A readiness latch starts tripped. */\nexport const LATCH_MACHINE: Machine = {\n ...base(\"latch\", \"The latch of a policy, as a debounce\"),\n states: {\n tripped: { initial: true, note: \"a readiness latch starts here; a liveness latch starts released\" },\n released: {},\n },\n events: { \"poll.ok\": { kind: \"local\" }, \"poll.fail\": { kind: \"local\" } },\n knobs: {\n fail_after: { key: \"policies.<gate>.failAfter\", scope: \"check\", unit: \"count\", default: null },\n recover_after: { key: \"policies.<gate>.recoverAfter\", scope: \"check\", unit: \"count\", default: null },\n },\n timers: {},\n transitions: [\n t(\"pass\", \"released\", \"poll.ok\", \"released\"),\n t(\"fail-count\", \"released\", \"poll.fail\", \"released\", { guard: \"failures in sequence < fail_after\" }),\n t(\"trip\", \"released\", \"poll.fail\", \"tripped\", { guard: \"failures in sequence >= fail_after\" }),\n t(\"fail\", \"tripped\", \"poll.fail\", \"tripped\"),\n t(\"pass-count\", \"tripped\", \"poll.ok\", \"tripped\", { guard: \"passes in sequence < recover_after\" }),\n t(\"release\", \"tripped\", \"poll.ok\", \"released\", { guard: \"passes in sequence >= recover_after\" }),\n ],\n};\n\n/**\n * A window latch measures time on the monotonic clock from the first failure of a sequence, and\n * from the first pass after a trip.\n */\nexport const WINDOW_MACHINE: Machine = {\n ...base(\"window\", \"The latch of a policy, as a window\"),\n states: {\n released: { initial: true, note: \"a liveness latch starts here; a readiness latch starts tripped\" },\n failing: { note: \"the fail window runs\" },\n tripped: {},\n recovering: { note: \"the recover window runs\" },\n },\n events: {\n \"poll.ok\": { kind: \"local\" },\n \"poll.fail\": { kind: \"local\" },\n \"window.failed\": { kind: \"timer\" },\n \"window.recovered\": { kind: \"timer\" },\n },\n knobs: {\n fail_after: { key: \"policies.<gate>.failAfter\", scope: \"check\", unit: \"s\", default: null },\n recover_after: { key: \"policies.<gate>.recoverAfter\", scope: \"check\", unit: \"s\", default: null },\n },\n timers: {\n fail_window: {\n duration: { knob: \"fail_after\", unit: \"s\" },\n arms: [\"enter:failing\"],\n cancels: [\"poll.ok\"],\n fires: \"window.failed\",\n },\n recover_window: {\n duration: { knob: \"recover_after\", unit: \"s\" },\n arms: [\"enter:recovering\"],\n cancels: [\"poll.fail\"],\n fires: \"window.recovered\",\n },\n },\n transitions: [\n t(\"pass\", \"released\", \"poll.ok\", \"released\"),\n t(\"start-failing\", \"released\", \"poll.fail\", \"failing\", { guard: \"fail_after > 0\" }),\n t(\"trip-at-once\", \"released\", \"poll.fail\", \"tripped\", { guard: \"fail_after = 0\" }),\n t(\"still-failing\", \"failing\", \"poll.fail\", \"failing\"),\n t(\"stop-failing\", \"failing\", \"poll.ok\", \"released\"),\n t(\"trip\", \"failing\", \"window.failed\", \"tripped\", { timer: \"fail_window\" }),\n t(\"fail\", \"tripped\", \"poll.fail\", \"tripped\"),\n t(\"release-at-once\", \"tripped\", \"poll.ok\", \"released\", { guard: \"recover_after is absent or 0\" }),\n t(\"start-recovering\", \"tripped\", \"poll.ok\", \"recovering\", { guard: \"recover_after > 0\" }),\n t(\"still-recovering\", \"recovering\", \"poll.ok\", \"recovering\"),\n t(\"stop-recovering\", \"recovering\", \"poll.fail\", \"tripped\"),\n t(\"release\", \"recovering\", \"window.recovered\", \"released\", { timer: \"recover_window\" }),\n ],\n};\n\n/**\n * A poller starts one check on a jittered loop with a fixed delay. A call that outlives its timeout\n * stays pending (`hung`), and the poller does not start the check again until the call settles.\n */\nexport const POLLER_MACHINE: Machine = {\n ...base(\"poller\", \"The poller of a check\"),\n states: {\n idle: { initial: true, note: \"before the loop starts\" },\n waiting: { note: \"the loop timer runs, and no call is pending\" },\n calling: { note: \"a call runs, in its timeout\" },\n hung: { note: \"a call outlived its timeout, and it is still pending\" },\n stopped: { final: true },\n },\n events: {\n start: { kind: \"local\" },\n sweep: { kind: \"local\" },\n tick: { kind: \"timer\" },\n answer: { kind: \"local\" },\n timeout: { kind: \"timer\" },\n \"late-answer\": { kind: \"local\" },\n stop: { kind: \"local\" },\n },\n knobs: {\n interval: { key: \"checks.<name>.poll.interval\", scope: \"check\", unit: \"s\", default: null },\n timeout: { key: \"checks.<name>.poll.timeout\", scope: \"check\", unit: \"s\", default: null },\n },\n timers: {\n loop: {\n duration: { knob: \"interval\", unit: \"s\" },\n arms: [\"start\", \"tick\"],\n cancels: [\"stop\"],\n fires: \"tick\",\n note: \"the interval, with its jitter: a fixed delay from the start of each poll\",\n },\n poll_timeout: {\n duration: { knob: \"timeout\", unit: \"s\" },\n arms: [\"enter:calling\"],\n cancels: [\"answer\", \"stop\"],\n fires: \"timeout\",\n },\n },\n transitions: [\n t(\"sweep\", \"idle\", \"sweep\", \"calling\"),\n t(\"start\", \"idle\", \"start\", \"waiting\"),\n t(\"start-while-calling\", \"calling\", \"start\", \"calling\", { note: \"a late check polls at once, then starts its loop\" }),\n t(\"start-while-hung\", \"hung\", \"start\", \"hung\"),\n t(\"tick\", \"waiting\", \"tick\", \"calling\", { guard: \"the force-fail list does not name the check\" }),\n t(\"tick-forced\", \"waiting\", \"tick\", \"waiting\", { guard: \"the force-fail list names the check\" }),\n t(\"tick-pending\", \"calling\", \"tick\", \"calling\", { note: \"the poll fails at once: its call is pending\" }),\n t(\"tick-hung\", \"hung\", \"tick\", \"hung\", { note: \"the poll fails at once: its call is pending\" }),\n t(\"answer-loop\", \"calling\", \"answer\", \"waiting\", { guard: \"the loop runs\" }),\n t(\"answer-sweep\", \"calling\", \"answer\", \"idle\", { guard: \"the loop has not started\" }),\n t(\"timeout\", \"calling\", \"timeout\", \"hung\", { timer: \"poll_timeout\" }),\n t(\"late-answer-loop\", \"hung\", \"late-answer\", \"waiting\", { guard: \"the loop runs\" }),\n t(\"late-answer-sweep\", \"hung\", \"late-answer\", \"idle\", { guard: \"the loop has not started\" }),\n t(\"stop\", [\"idle\", \"waiting\", \"calling\", \"hung\"], \"stop\", \"stopped\"),\n t(\"settle-after-stop\", \"stopped\", [\"answer\", \"late-answer\", \"timeout\"], \"stopped\"),\n ],\n};\n\n/**\n * The exit manager is the only part that ends the process. The first exit request starts the\n * shutdown. A later request has no effect, but a repeat signal exits at once when the declaration\n * says `onRepeatSignal: \"exit\"`. The exit code is the code of the exit request, else 1 after an\n * error, else 0.\n */\nexport const EXIT_MACHINE: Machine = {\n ...base(\"exit\", \"The exit manager\"),\n states: { running: { initial: true }, stopping: {}, exited: { final: true } },\n events: {\n \"exit.request\": { kind: \"app\", note: \"SIGINT, SIGTERM, SIGQUIT, a declared process trigger or shutdown()\" },\n \"exit.repeat\": { kind: \"app\", note: \"a trigger or shutdown() while the shutdown runs\" },\n \"startup.fail\": { kind: \"local\" },\n error: { kind: \"local\" },\n \"shutdown.done\": { kind: \"local\" },\n },\n knobs: {\n on_repeat_signal: { key: \"shutdown.onRepeatSignal\", scope: \"service\", unit: null, default: null },\n },\n timers: {},\n transitions: [\n t(\"request\", \"running\", \"exit.request\", \"stopping\"),\n t(\"startup-fail\", \"running\", \"startup.fail\", \"stopping\"),\n t(\"error-running\", \"running\", \"error\", \"running\"),\n t(\"repeat\", \"stopping\", \"exit.repeat\", \"stopping\", {\n guard: \"a process trigger or shutdown() repeats, or a signal repeats and on_repeat_signal is not exit\",\n }),\n t(\"repeat-exit\", \"stopping\", \"exit.repeat\", \"exited\", {\n guard: \"a signal repeats and on_repeat_signal is exit\",\n note: \"the process exits at once with the code 1\",\n }),\n t(\"startup-fail-stopping\", \"stopping\", \"startup.fail\", \"stopping\"),\n t(\"error\", \"stopping\", \"error\", \"stopping\"),\n t(\"exit\", \"stopping\", \"shutdown.done\", \"exited\", {\n note: \"the exit code is the code of the exit request, else 1 after an error, else 0\",\n }),\n ],\n};\n\n/** A watchdog measures how late its own tick comes, and a late tick shows a blocked event loop. */\nexport const WATCHDOG_MACHINE: Machine = {\n ...base(\"watchdog\", \"The watchdog of the event loop\"),\n states: { watching: { initial: true }, blocked: {}, stopped: { final: true } },\n events: { tick: { kind: \"timer\" }, stop: { kind: \"local\" } },\n knobs: {\n tick: { key: \"watchdog.tick\", scope: \"process\", unit: \"s\", default: null },\n threshold: { key: \"watchdog.threshold\", scope: \"process\", unit: \"s\", default: null },\n },\n timers: {\n tick: { duration: { knob: \"tick\", unit: \"s\" }, arms: [\"enter:watching\", \"tick\"], cancels: [\"stop\"], fires: \"tick\" },\n },\n transitions: [\n t(\"on-time\", \"watching\", \"tick\", \"watching\", { guard: \"lateness <= threshold\" }),\n t(\"block\", \"watching\", \"tick\", \"blocked\", { guard: \"lateness > threshold\" }),\n t(\"still-blocked\", \"blocked\", \"tick\", \"blocked\", { guard: \"lateness > threshold\" }),\n t(\"unblock\", \"blocked\", \"tick\", \"watching\", { guard: \"lateness <= threshold\" }),\n t(\"stop\", [\"watching\", \"blocked\"], \"stop\", \"stopped\"),\n ],\n};\n\n/** This function gives the name of a knob for the cap of a phase: `drain` gives `drain_cap`. */\nexport const capKnob = (phase: string): string => `${phase.replace(/[^A-Za-z0-9]+/g, \"_\")}_cap`;\n\n/**\n * This function gives the drain of a declaration as a machine. It has one state for each declared\n * phase, in its sequence, and each state has a timer at its cap. The drain also has the cooperative abort: the\n * cap of the drain less the cooperative window. With the floor `half`, it is half that cap at the\n * least. With the floor `none`, it is 0 at the least.\n */\nexport const drainMachine = (description: ServiceDescription): Machine => {\n const phases = description.shutdown.phases;\n const states: Record<string, { initial?: boolean; final?: boolean; note?: string }> = {\n running: { initial: true },\n };\n for (const phase of phases) states[phase.name] = {};\n states[\"done\"] = { final: true };\n const knobs: Machine[\"knobs\"] = Object.fromEntries([\n ...phases.map((phase) => [\n capKnob(phase.name),\n { key: `shutdown.phases.${phase.name}.cap`, scope: \"service\", unit: \"s\", default: null },\n ]),\n [\"cooperative_window\", { key: \"shutdown.cooperativeWindow\", scope: \"service\", unit: \"s\", default: null }],\n ]);\n const timers: Record<string, Machine[\"timers\"][string]> = {};\n for (const phase of phases)\n timers[`${capKnob(phase.name)}_timer`] = {\n duration: { knob: capKnob(phase.name), unit: \"s\" },\n arms: [`enter:${phase.name}`],\n cancels: [\"phase.done\"],\n fires: \"phase.cap\",\n };\n // the floor of the cooperative abort is half the cap, or 0 for a declaration without a floor\n const floor = description.shutdown.cooperativeFloor === \"none\" ? \"0\" : \"drain_cap / 2\";\n if (phases.some((phase) => phase.name === \"drain\"))\n timers[\"cooperative_abort\"] = {\n duration: { expr: `max(drain_cap - cooperative_window, ${floor})`, unit: \"s\" },\n arms: [\"enter:drain\"],\n cancels: [\"phase.done\", \"phase.cap\"],\n fires: \"drain.cooperative-abort\",\n };\n const transitions: TransitionDef[] = [];\n const order = [\"running\", ...phases.map((phase) => phase.name), \"done\"];\n for (let at = 0; at + 1 < order.length; at += 1) {\n const from = order[at]!;\n const to = order[at + 1]!;\n transitions.push(\n at === 0\n ? t(`begin`, from, \"exit.request\", to)\n : t(`after-${from}`, from, [\"phase.done\", \"phase.cap\"], to, {\n timer: `${capKnob(from)}_timer`,\n note: \"phase.cap: the work of the phase did not end in its cap, and the exit code is 1\",\n }),\n );\n }\n if (phases.some((phase) => phase.name === \"drain\"))\n transitions.push(t(\"cooperative-abort\", \"drain\", \"drain.cooperative-abort\", \"drain\", { timer: \"cooperative_abort\" }));\n // the signal of the service aborts when the sequence passes the poller, or at the end: it leaves\n // the drain where it is\n for (const state of [...phases.map((phase) => phase.name), \"done\"])\n transitions.push(t(`signal-abort-${state}`, state, \"signal.abort\", state));\n return {\n ...base(\"drain\", `The drain of ${description.name}`),\n states,\n events: {\n \"exit.request\": { kind: \"app\" },\n \"phase.done\": { kind: \"local\" },\n \"phase.cap\": { kind: \"timer\" },\n \"drain.cooperative-abort\": { kind: \"timer\" },\n \"signal.abort\": { kind: \"local\" },\n },\n knobs,\n timers,\n transitions,\n };\n};\n\n/** These are the static machines of the runtime, by the name that their events carry. */\nexport const MACHINES: Readonly<Record<Exclude<MachineName, \"drain\" | \"client\">, Machine>> = {\n gate: GATE_MACHINE,\n latch: LATCH_MACHINE,\n window: WINDOW_MACHINE,\n poller: POLLER_MACHINE,\n exit: EXIT_MACHINE,\n watchdog: WATCHDOG_MACHINE,\n};\n"],"mappings":"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"}
|