internal/jobs persists jobs in the jobs table, which is also the queue: a
bounded pool of workers claims queued jobs oldest first. Handlers are
registered per kind before Start with typed payloads and results, and can
publish partial results to the row while they run. Only typed results and
*jobs.Failure messages are stored; any other handler error is logged and
stored as "internal error", so dependency error text cannot surface a
secret. Start fails jobs a previous process left running with
"interrupted by restart" before any worker runs.
GET /api/v1/jobs/{id} returns {id, kind, status, result, error} inside the
protected /api/v1 group; an unknown id is a 404 not_found.
Migration 0003_jobs_status rebuilds jobs with status queued, running,
succeeded, failed, mapping legacy pending and done rows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
167 lines
3.8 KiB
Go
167 lines
3.8 KiB
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
// source: jobs.sql
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
)
|
|
|
|
const claimNextJob = `-- name: ClaimNextJob :one
|
|
UPDATE jobs
|
|
SET status = 'running', started_at = ?1, updated_at = ?1
|
|
WHERE id = (SELECT id FROM jobs WHERE status = 'queued' ORDER BY id LIMIT 1)
|
|
RETURNING id, kind, status, payload, result, error, started_at, finished_at, created_at, updated_at
|
|
`
|
|
|
|
// Marks the oldest queued job running and returns it. Returns sql.ErrNoRows
|
|
// when no job is queued.
|
|
func (q *Queries) ClaimNextJob(ctx context.Context, now sql.NullString) (Job, error) {
|
|
row := q.db.QueryRowContext(ctx, claimNextJob, now)
|
|
var i Job
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.Kind,
|
|
&i.Status,
|
|
&i.Payload,
|
|
&i.Result,
|
|
&i.Error,
|
|
&i.StartedAt,
|
|
&i.FinishedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const createJob = `-- name: CreateJob :exec
|
|
INSERT INTO jobs (id, kind, status, payload, created_at, updated_at)
|
|
VALUES (?, ?, 'queued', ?, ?, ?)
|
|
`
|
|
|
|
type CreateJobParams struct {
|
|
ID string
|
|
Kind string
|
|
Payload string
|
|
CreatedAt string
|
|
UpdatedAt string
|
|
}
|
|
|
|
func (q *Queries) CreateJob(ctx context.Context, arg CreateJobParams) error {
|
|
_, err := q.db.ExecContext(ctx, createJob,
|
|
arg.ID,
|
|
arg.Kind,
|
|
arg.Payload,
|
|
arg.CreatedAt,
|
|
arg.UpdatedAt,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const failJob = `-- name: FailJob :execrows
|
|
UPDATE jobs
|
|
SET status = 'failed', error = ?1, finished_at = ?2, updated_at = ?2
|
|
WHERE id = ?3 AND status = 'running'
|
|
`
|
|
|
|
type FailJobParams struct {
|
|
Error sql.NullString
|
|
Now sql.NullString
|
|
ID string
|
|
}
|
|
|
|
func (q *Queries) FailJob(ctx context.Context, arg FailJobParams) (int64, error) {
|
|
result, err := q.db.ExecContext(ctx, failJob, arg.Error, arg.Now, arg.ID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected()
|
|
}
|
|
|
|
const failRunningJobs = `-- name: FailRunningJobs :execrows
|
|
UPDATE jobs
|
|
SET status = 'failed', error = ?1, finished_at = ?2, updated_at = ?2
|
|
WHERE status = 'running'
|
|
`
|
|
|
|
type FailRunningJobsParams struct {
|
|
Error sql.NullString
|
|
Now sql.NullString
|
|
}
|
|
|
|
// Fails every job left running, at boot before any worker starts.
|
|
func (q *Queries) FailRunningJobs(ctx context.Context, arg FailRunningJobsParams) (int64, error) {
|
|
result, err := q.db.ExecContext(ctx, failRunningJobs, arg.Error, arg.Now)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected()
|
|
}
|
|
|
|
const getJob = `-- name: GetJob :one
|
|
SELECT id, kind, status, payload, result, error, started_at, finished_at, created_at, updated_at FROM jobs
|
|
WHERE id = ?
|
|
`
|
|
|
|
func (q *Queries) GetJob(ctx context.Context, id string) (Job, error) {
|
|
row := q.db.QueryRowContext(ctx, getJob, id)
|
|
var i Job
|
|
err := row.Scan(
|
|
&i.ID,
|
|
&i.Kind,
|
|
&i.Status,
|
|
&i.Payload,
|
|
&i.Result,
|
|
&i.Error,
|
|
&i.StartedAt,
|
|
&i.FinishedAt,
|
|
&i.CreatedAt,
|
|
&i.UpdatedAt,
|
|
)
|
|
return i, err
|
|
}
|
|
|
|
const publishJobResult = `-- name: PublishJobResult :execrows
|
|
UPDATE jobs
|
|
SET result = ?, updated_at = ?
|
|
WHERE id = ? AND status = 'running'
|
|
`
|
|
|
|
type PublishJobResultParams struct {
|
|
Result sql.NullString
|
|
UpdatedAt string
|
|
ID string
|
|
}
|
|
|
|
// Stores a partial result of a running job.
|
|
func (q *Queries) PublishJobResult(ctx context.Context, arg PublishJobResultParams) (int64, error) {
|
|
result, err := q.db.ExecContext(ctx, publishJobResult, arg.Result, arg.UpdatedAt, arg.ID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected()
|
|
}
|
|
|
|
const succeedJob = `-- name: SucceedJob :execrows
|
|
UPDATE jobs
|
|
SET status = 'succeeded', result = ?1, finished_at = ?2, updated_at = ?2
|
|
WHERE id = ?3 AND status = 'running'
|
|
`
|
|
|
|
type SucceedJobParams struct {
|
|
Result sql.NullString
|
|
Now sql.NullString
|
|
ID string
|
|
}
|
|
|
|
func (q *Queries) SucceedJob(ctx context.Context, arg SucceedJobParams) (int64, error) {
|
|
result, err := q.db.ExecContext(ctx, succeedJob, arg.Result, arg.Now, arg.ID)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return result.RowsAffected()
|
|
}
|