Skip to content

Jobs

The jobs endpoints manage the full maintenance job lifecycle — submission, monitoring, cancellation, and deletion. All maintenance work is asynchronous: you submit a job, receive a 202 Accepted, and poll for completion.

Jobs are stored in the jobs Postgres table. A job_queue table manages dispatch to workers, and a table_locks table prevents concurrent maintenance on the same table.


Submit maintenance job

POST /tables/{database}/{table}/maintenance

Submits a new maintenance job for the given table. The API validates the requested actions, acquires a table lock, persists the job to Postgres, and enqueues it for worker pickup.

Path parameters

ParameterTypeDescription
databasestringDatabase name.
tablestringTable name.

Request body

{
"actions": ["rewrite_data_files", "expire_snapshots"],
"dry_run": false
}
FieldTypeRequiredDefaultDescription
actionsstring[]YesMaintenance actions to run. At least one required.
dry_runbooleanNofalseWhen true, validates and returns immediately without running.

Valid actions (always executed in this order):

  1. rewrite_data_files
  2. rewrite_position_delete_files
  3. rewrite_manifests
  4. expire_snapshots
  5. remove_orphan_files

Response — 202 Accepted

{
"job_id": "a1b2c3d4e5f678901234567890abcdef",
"database": "analytics",
"table_name": "page_views",
"actions": ["rewrite_data_files", "expire_snapshots"],
"dry_run": false,
"status": "pending",
"submitted_at": "2026-04-25T14:35:00.000000+00:00",
"started_at": null,
"completed_at": null,
"results": null,
"error": null
}

Response headers:

HeaderValueDescription
Location/jobs/{job_id}URL to poll for job status.
Retry-After30Suggested poll interval in seconds. Present for non-dry-run jobs.

Status codes

CodeMeaning
202Job accepted and queued (or completed immediately for dry runs).
400Empty actions list or invalid action name.
404Table not found in the table cache.
409Maintenance already in progress for this table (table lock held).
422Invalid database or table name.
503Drain mode is enabled — ingestion is paused for backend migration.

Example

Terminal window
curl -X POST https://snowpack-api.internal/tables/analytics/page_views/maintenance \
-H "Content-Type: application/json" \
-d '{"actions": ["rewrite_data_files", "expire_snapshots"]}'

Dry run (validates without executing):

Terminal window
curl -X POST https://snowpack-api.internal/tables/analytics/page_views/maintenance \
-H "Content-Type: application/json" \
-d '{"actions": ["rewrite_data_files"], "dry_run": true}'

List jobs

GET /jobs

Returns active jobs from the jobs Postgres table. Use query parameters to narrow results by table or status.

Query parameters

ParameterTypeDescription
tablestringFilter by table in database.table_name format.
statusstringFilter by status: pending, running, completed, failed, or cancelled.

Response — 200 OK

[
{
"job_id": "a1b2c3d4e5f678901234567890abcdef",
"database": "analytics",
"table_name": "page_views",
"actions": ["rewrite_data_files", "expire_snapshots"],
"dry_run": false,
"status": "running",
"submitted_at": "2026-04-25T14:35:00.000000+00:00",
"started_at": "2026-04-25T14:35:05.000000+00:00",
"completed_at": null,
"results": null,
"error": null
}
]

Status codes

CodeMeaning
200Success.

Example

Terminal window
# All jobs
curl https://snowpack-api.internal/jobs
# Only running jobs for a specific table
curl "https://snowpack-api.internal/jobs?table=analytics.page_views&status=running"

Get job

GET /jobs/{job_id}

Returns a single job with full details, including per-action results once the job completes.

While the job is pending or running, the response includes a Retry-After: 30 header as a hint for poll-based clients.

Path parameters

ParameterTypeDescription
job_idstringThe job ID (hex).

Response — 200 OK

{
"job_id": "a1b2c3d4e5f678901234567890abcdef",
"database": "analytics",
"table_name": "page_views",
"actions": ["rewrite_data_files", "expire_snapshots"],
"dry_run": false,
"status": "completed",
"submitted_at": "2026-04-25T14:35:00.000000+00:00",
"started_at": "2026-04-25T14:35:05.000000+00:00",
"completed_at": "2026-04-25T14:38:22.000000+00:00",
"results": [
{
"action": "rewrite_data_files",
"success": true,
"message": "Compacted 87 files into 12",
"error": null,
"elapsed_seconds": 142.3
},
{
"action": "expire_snapshots",
"success": true,
"message": "Expired 28 snapshots",
"error": null,
"elapsed_seconds": 5.1
}
],
"error": null
}

The results array contains one entry per action, each with:

FieldTypeDescription
actionstringAction name.
successbooleanWhether the action succeeded.
messagestringHuman-readable summary.
errorstring|nullError details if the action failed.
elapsed_secondsfloatWall-clock time for this action.

Response headers

HeaderConditionValue
Retry-AfterJob is pending or running30

Status codes

CodeMeaning
200Success.
404Job not found.

Example

Terminal window
curl https://snowpack-api.internal/jobs/a1b2c3d4e5f678901234567890abcdef

Cancel job

POST /jobs/{job_id}/cancel

Cancels a pending or running job. This operation runs in a single Postgres transaction that:

  1. Acquires a row lock on the job (SELECT ... FOR UPDATE).
  2. Sets status to cancelled and revokes the fence token (attempt_id = NULL), so any in-flight worker will no-op on its next write.
  3. Deletes the job_queue row to prevent worker pickup.
  4. Releases the table_locks entry if the job was still pending (not yet claimed by a worker).

For running jobs, the worker detects the fence revocation in its finally block and releases the table lock at that point.

Path parameters

ParameterTypeDescription
job_idstringThe job ID (hex).

Response — 200 OK

Returns the updated job object with status: "cancelled".

{
"job_id": "a1b2c3d4e5f678901234567890abcdef",
"database": "analytics",
"table_name": "page_views",
"actions": ["rewrite_data_files"],
"dry_run": false,
"status": "cancelled",
"submitted_at": "2026-04-25T14:35:00.000000+00:00",
"started_at": null,
"completed_at": "2026-04-25T14:36:10.000000+00:00",
"results": null,
"error": "Cancelled by user"
}

Status codes

CodeMeaning
200Job cancelled successfully.
404Job not found (or already soft-deleted).
409Job is already in a terminal state (completed, failed, or cancelled).

Example

Terminal window
curl -X POST https://snowpack-api.internal/jobs/a1b2c3d4e5f678901234567890abcdef/cancel

Delete job

DELETE /jobs/{job_id}

Soft-deletes a job by setting a deleted_at tombstone. Only terminal jobs (completed, failed, or cancelled) can be deleted. Active jobs must be cancelled first.

The job row remains in Postgres for audit purposes but is excluded from normal queries.

Path parameters

ParameterTypeDescription
job_idstringThe job ID (hex).

Response — 204 No Content

No response body.

Status codes

CodeMeaning
204Job soft-deleted.
404Job not found.
409Job is still pending or running. Cancel it first.

Example

Terminal window
curl -X DELETE https://snowpack-api.internal/jobs/a1b2c3d4e5f678901234567890abcdef