import type { CommandResult } from './types/command'; /** * How long a pending result stays on disk before it is discarded. * * This MUST outlive the server-side command timeout. The API keeps a claimed * command in RUNNING for `MAX_COMMAND_EXECUTION_MS` (2 hours, see * api/src/common/constants/agent.constants.ts) before sweeping it to TIMEOUT. * The previous value was 1 hour, so the agent deleted the result a full hour * *before* the server stopped waiting for it — the job was then reported as * TIMEOUT even though it had completed successfully. */ export declare const PENDING_RESULT_STALE_THRESHOLD_MS: number; /** * How often to retry submitting results that are still on disk. * * A production API rollover takes roughly 85 seconds end to end (measured * 2026-08-16: stoppingAt 12:55:24 → stoppedAt 12:56:49). Retrying every minute * recovers an orphaned result within one deployment window. */ export declare const PENDING_RESULT_FLUSH_INTERVAL_MS: number; /** * Minimum age a pending result must reach before the *periodic* flush touches it. * * The main path writes the file BEFORE calling `submitResult` (agent-transport.ts), * precisely so a crash mid-submit cannot lose the result. That submit can take up * to ~35s (API_REQUEST_TIMEOUT 10s x API_MAX_RETRIES 3, plus backoff). Without this * guard the flush would pick up a file whose main-path submit is still in flight and * POST the same result in parallel — a race that did not exist when * `submitPendingResults()` only ran at process start. * * The server is idempotent (duplicate results are ignored), so this is about not * relying on that: a client-side race would show up as `duplicate_ignored` warnings * in production logs exactly when things are already going wrong. * * Only the very first registration of a process passes no minimum age (nothing can be * in flight yet). `registerAndStart()` also runs on token update and on eviction → * re-admission, where commands started earlier are still running, so those passes must * apply the guard too (see `ProjectAgent.hasRecoveredPendingResults`). */ export declare const PENDING_RESULT_MIN_RETRY_AGE_MS: number; export interface PendingResult { commandId: string; agentId: string; result: CommandResult; apiUrl: string; token: string; tenantCode: string; savedAt: string; /** * 結果を生成したレプリカの instanceId。 * * 再起動後の再送では、コマンドのクレーム主は「保存時のプロセス」のままである。 * 現在のプロセスの instanceId(Pod 名は再作成で変わる)で送るとサーバー側の * フェンシングで 409 になり、実行済みの結果が破棄される。 * 旧バージョンが書いたファイルには存在しないため optional。 */ instanceId?: string; /** * 結果を生成した実行の指名世代(フェンシングトークン)。 * * instanceId だけでは足りない。世代を送らないとサーバーは「指名を名乗らない * クライアント」として扱い、指名済みコマンドへの書き込みを拒否する(409)。 * その 409 は「別レプリカに奪われた」と解釈されて結果が破棄されるため、 * 同一 Pod のクラッシュ→再起動という最も典型的なケースで結果が失われる。 */ assignmentGeneration?: number; } export declare function savePendingResult(commandId: string, agentId: string, result: CommandResult, apiUrl: string, token: string, tenantCode: string, assignmentGeneration?: number): boolean; export declare function removePendingResult(commandId: string): void; export declare function loadPendingResults(): PendingResult[]; export declare function submitPendingResults(options?: { minAgeMs?: number; }): Promise; /** * Start retrying pending results on an interval. * * `submitPendingResults()` alone runs once per process start, but the agent is a * long-lived process that does NOT restart when the API is deployed. Without a * periodic retry, a result orphaned by a rollover stays on disk until the agent * happens to restart — which in practice means it is discarded by the stale * cleanup and the job is reported as TIMEOUT despite having succeeded. * * Returns the timer so the caller can stop it (see `ProjectAgent.stopWork()`). */ export declare function startPendingResultFlush(intervalMs?: number): ReturnType; //# sourceMappingURL=pending-result-store.d.ts.map