/** * One capacity policy for the Absurd runtime. * * Postgres owns backlog. The active lane adds workers from durable claimable * demand and oldest-claimable age; historical lanes stay cold unless they own * runnable work. Keep these values together so the worker, scaler, gateway, * and tests cannot independently invent concurrency or timeout budgets. */ export const RUNTIME_CAPACITY_POLICY = { absurd: { /** Warm floor for availability and deploy rollovers. */ activeLaneMachines: 2, /** 32 Machines x 8 claim slots permits 256 concurrent launch/resume legs. */ maxActiveLaneMachines: 32, workerSlotsPerMachine: 8, /** Queue age is an escape hatch for small-but-stuck backlogs. */ scaleUpQueueAgeMs: 10_000, /** Bound one Fly reconciliation without turning backlog into a stampede. */ maxScaleUpMachinesPerReconcile: 4, /** Do not tear down burst capacity on the first empty observation. */ scaleDownQuietMs: 120_000, }, receiptGateway: { admissionTimeoutMs: 10_000, /** End identical receipt-row work before the caller can overlap a retry. */ claimOperationTimeoutMs: 20_000, requestTimeoutMs: 30_000, }, } as const; export const ABSURD_GLOBAL_RUN_CONCURRENCY = RUNTIME_CAPACITY_POLICY.absurd.maxActiveLaneMachines * RUNTIME_CAPACITY_POLICY.absurd.workerSlotsPerMachine; /** * Active releases use pg-boss-style burst semantics: claimable count sets the * target, an aged claimable queue forces continued growth, and growth per * observation is bounded. A short/empty observation ends burst growth; the * caller supplies idleForMs to hold excess capacity through a quiet window. * * Historical releases stay cold until they have immediately runnable or * currently claimed work. */ export function desiredAbsurdLaneMachines(input: { active: boolean; claimableRuns: number; runningRuns?: number; currentMachines?: number; oldestClaimableAgeMs?: number; idleForMs?: number; }): number { const claimableRuns = nonNegativeInteger(input.claimableRuns); const runningRuns = nonNegativeInteger(input.runningRuns ?? 0); if (!input.active) return claimableRuns > 0 || runningRuns > 0 ? 1 : 0; const policy = RUNTIME_CAPACITY_POLICY.absurd; const currentMachines = Math.max( policy.activeLaneMachines, nonNegativeInteger(input.currentMachines ?? policy.activeLaneMachines), ); const demandedMachines = Math.ceil( (claimableRuns + runningRuns) / policy.workerSlotsPerMachine, ); let desired = Math.max(policy.activeLaneMachines, demandedMachines); if ( claimableRuns > 0 && nonNegativeNumber(input.oldestClaimableAgeMs ?? 0) >= policy.scaleUpQueueAgeMs ) { desired = Math.max(desired, currentMachines + 1); } desired = Math.min( desired, currentMachines + policy.maxScaleUpMachinesPerReconcile, policy.maxActiveLaneMachines, ); if ( claimableRuns === 0 && runningRuns === 0 && nonNegativeNumber(input.idleForMs ?? 0) < policy.scaleDownQuietMs ) { desired = Math.max(desired, currentMachines); } return desired; } function nonNegativeInteger(value: number): number { return Math.max(0, Math.floor(nonNegativeNumber(value))); } function nonNegativeNumber(value: number): number { return Number.isFinite(value) ? Math.max(0, value) : 0; } export function assertRuntimeCapacityPolicy(): void { if ( RUNTIME_CAPACITY_POLICY.receiptGateway.requestTimeoutMs <= RUNTIME_CAPACITY_POLICY.receiptGateway.admissionTimeoutMs ) { throw new Error( 'Receipt gateway request timeout must exceed its admission timeout.', ); } if ( RUNTIME_CAPACITY_POLICY.receiptGateway.claimOperationTimeoutMs + 5_000 > RUNTIME_CAPACITY_POLICY.receiptGateway.requestTimeoutMs ) { throw new Error( 'Receipt claim operations must leave at least five seconds for cancellation and response delivery.', ); } if ( RUNTIME_CAPACITY_POLICY.absurd.activeLaneMachines > RUNTIME_CAPACITY_POLICY.absurd.maxActiveLaneMachines ) { throw new Error( 'Active-lane minimum Machines cannot exceed the active-lane maximum.', ); } } assertRuntimeCapacityPolicy();