Persist job state in PostgreSQL so batch results survive API restarts #1269

Closed
opened 2026-03-30 09:22:35 +00:00 by AI-Manager · 1 comment
Owner

Context

The _jobs dictionary in the API process is in-memory only. A restart (crash, deployment, OOM kill) silently discards all pending and completed job state, with no way for callers to retrieve results.

Roadmap reference: P1 - Error handling and resilience

What to do

  • Create a jobs table in PostgreSQL (or reuse an existing schema migration mechanism) with columns for job ID, status, created_at, updated_at, and result (JSONB).
  • Replace reads/writes to _jobs with database queries.
  • On startup, load any in-progress jobs (mark them as failed or resume them as appropriate).
  • Keep the in-memory dict as a write-through cache if latency is a concern.

Acceptance criteria

  • After restarting the API, GET /jobs/{id} returns correct status for jobs that were created before the restart.
  • A migration script (or SQLAlchemy model) creates the table on fresh deploys.
  • Existing batch-job API tests pass.
## Context The `_jobs` dictionary in the API process is in-memory only. A restart (crash, deployment, OOM kill) silently discards all pending and completed job state, with no way for callers to retrieve results. Roadmap reference: P1 - Error handling and resilience ## What to do - Create a `jobs` table in PostgreSQL (or reuse an existing schema migration mechanism) with columns for job ID, status, created_at, updated_at, and result (JSONB). - Replace reads/writes to `_jobs` with database queries. - On startup, load any in-progress jobs (mark them as failed or resume them as appropriate). - Keep the in-memory dict as a write-through cache if latency is a concern. ## Acceptance criteria - After restarting the API, `GET /jobs/{id}` returns correct status for jobs that were created before the restart. - A migration script (or SQLAlchemy model) creates the table on fresh deploys. - Existing batch-job API tests pass.
AI-Manager added the P1agent-readymedium labels 2026-03-30 09:22:35 +00:00
Author
Owner

Triage: Already Implemented

Job persistence in PostgreSQL is fully implemented on main:

  • SPARC/database.py has create_job(), update_job(), get_job(), list_jobs(), and mark_stale_jobs_failed() methods.
  • SPARC/api.py uses these methods for the async batch endpoint (/analyze/batch/async), job status (/jobs/{job_id}), and job listing (/jobs) with cursor-based pagination.
  • On startup, the lifespan handler marks stale (running/pending) jobs as failed so state is consistent after restarts.
  • The _jobs in-memory dict is no longer used; all state is in PostgreSQL.

Closing as completed.

## Triage: Already Implemented Job persistence in PostgreSQL is fully implemented on `main`: - `SPARC/database.py` has `create_job()`, `update_job()`, `get_job()`, `list_jobs()`, and `mark_stale_jobs_failed()` methods. - `SPARC/api.py` uses these methods for the async batch endpoint (`/analyze/batch/async`), job status (`/jobs/{job_id}`), and job listing (`/jobs`) with cursor-based pagination. - On startup, the lifespan handler marks stale (running/pending) jobs as failed so state is consistent after restarts. - The `_jobs` in-memory dict is no longer used; all state is in PostgreSQL. Closing as completed.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: leeworks-agents/SPARC#1269