/** * Deriver Queue — Queue Manager * * Implements claim/complete/fail/stale-recovery operations for the * deriver_queue table using SQLite WAL with BEGIN IMMEDIATE for safe * concurrent single-node access. * * Claim pattern (analogous to PostgreSQL FOR UPDATE SKIP LOCKED): * BEGIN IMMEDIATE * SELECT ... WHERE status='pending' ORDER BY priority DESC, created_at ASC LIMIT 1 * UPDATE ... SET status='in_progress', claimed_at=now, claimed_by=workerId * COMMIT * * SQLite serializes WAL writes via the WAL journal, so two concurrent * callers with BEGIN IMMEDIATE will take turns safely. * * @task T1145 * @epic T1145 */ import type { DatabaseSync } from 'node:sqlite'; /** Max stale claim age in minutes before item is re-queued. */ export declare const STALE_CLAIM_MINUTES = 30; /** Max retry count before item is moved to 'failed' permanently. */ export declare const MAX_RETRY_COUNT = 5; /** * Base exponential-backoff delay in seconds for a re-queued item (T10405). * * A failed/recovered item's next claim is gated until * `now + BACKOFF_BASE_SECONDS * 2^(retryCount - 1)`, capped at * {@link BACKOFF_MAX_SECONDS}. With base 30s the schedule is * 30s → 60s → 120s → 240s (then capped), so a transiently-failing item * backs off geometrically instead of hot-looping the worker. */ export declare const BACKOFF_BASE_SECONDS = 30; /** Maximum exponential-backoff delay in seconds (cap for {@link computeBackoffSeconds}). */ export declare const BACKOFF_MAX_SECONDS: number; /** Options for {@link claimNextItem}. */ export interface ClaimOptions { /** * Worker identifier. Used to track which process claimed the item. * Defaults to `worker--`. */ workerId?: string; /** Inject a DatabaseSync for testing. */ db?: DatabaseSync | null; } /** A claimed queue item. */ export interface ClaimedItem { id: string; itemType: string; itemId: string; priority: number; retryCount: number; } /** Options for {@link completeItem} and {@link failItem}. */ export interface CompleteOptions { /** Inject a DatabaseSync for testing. */ db?: DatabaseSync | null; } /** Result of a stale-claim recovery sweep. */ export interface StaleRecoveryResult { /** Number of items re-queued from in_progress to pending. */ requeued: number; /** Number of items permanently failed due to max retries. */ failed: number; } /** * Compute the exponential-backoff delay (seconds) for a re-queued item (T10405). * * Returns `BACKOFF_BASE_SECONDS * 2^(attempt - 1)` capped at * {@link BACKOFF_MAX_SECONDS}. `attempt` is the *new* retry count (1-based: * the first failure backs off by the base delay). An `attempt` of 0 or less is * clamped to 1 so the first retry always waits at least the base delay. * * @param attempt - The new (post-increment) retry count for the item. * @returns Backoff delay in seconds, in `[BACKOFF_BASE_SECONDS, BACKOFF_MAX_SECONDS]`. * * @task T10405 */ export declare function computeBackoffSeconds(attempt: number): number; /** * Claim the next pending item from the deriver queue. * * Uses BEGIN IMMEDIATE to serialize against concurrent callers in the same * process (e.g. test helpers). Returns null if no pending item exists or if * the database is busy. * * @param options - workerId override, db injection for tests. * @returns The claimed item, or null if queue is empty / DB busy. * * @task T1145 */ export declare function claimNextItem(options?: ClaimOptions): ClaimedItem | null; /** * Mark a claimed item as successfully completed. * * @param itemId - The deriver_queue.id to complete. * @param options - Optional db injection for tests. * * @task T1145 */ export declare function completeItem(itemId: string, options?: CompleteOptions): void; /** * Mark a claimed item as failed (with optional error message). * * If `retryCount` is below {@link MAX_RETRY_COUNT}, the item is re-queued * to `pending` with `retryCount + 1` and an exponential-backoff * `next_attempt_at` (T10405) so it is not re-claimed until the backoff window * elapses. Otherwise the item is permanently moved to `failed` (DLQ semantics) * and its backoff gate is cleared. * * @param itemId - The deriver_queue.id to fail. * @param errorMsg - Human-readable error for the error_msg column. * @param options - Optional db injection for tests. * * @task T1145 */ export declare function failItem(itemId: string, errorMsg: string, options?: CompleteOptions): void; /** * Re-queue stale in_progress items whose `claimed_at` is older than * {@link STALE_CLAIM_MINUTES} minutes. * * Items that have exceeded {@link MAX_RETRY_COUNT} are permanently moved * to `failed` instead of being re-queued. * * Designed to be called from `runBrainMaintenance` as a periodic health check. * * @param options - Optional db injection for tests. * @returns Count of items requeued and count permanently failed. * * @task T1145 */ export declare function recoverStaleItems(options?: CompleteOptions): StaleRecoveryResult; //# sourceMappingURL=queue-manager.d.ts.map