Skip to content

Job queue with a single claim — Examples

A worker queue often needs an invariant like “at most one pending job per (name, actor)” — while still allowing many finished rows with the same key. A partial unique constraint expresses exactly that: uniqueness that only applies to rows matching a filter.

enum QueueStatus { Pending, Running, Failed, Processed }
type Job {
required name: str;
required actor: str;
payload: json;
status: QueueStatus { default := QueueStatus.Pending };
claimed_at: datetime;
processed_at: datetime;
# Uniqueness only among Pending rows — Running/Failed/Processed are unconstrained.
constraint exclusive on (.name, .actor) filter .status = QueueStatus.Pending;
}

Postgres can’t attach a WHERE to a table UNIQUE, so this lowers to a partial unique index:

CREATE UNIQUE INDEX IF NOT EXISTS "uq_job_name_actor"
ON "job" ("name", "actor")
WHERE (status = 'Pending');

A second Pending job for the same (name, actor) now raises a unique-violation at insert time — the database refuses the duplicate:

insert Job { name := $name, actor := $actor, payload := $payload };

Catch that error in your worker and treat it as “already queued”.

Moving a job off Pending (to Running) drops it out of the partial index — so the same key can be enqueued again while the first one is still in flight:

update Job
filter .id = $id<uuid>
set { status := QueueStatus.Running, claimed_at := now() };
await runner.query.enqueueJob({ name, actor, payload }); // no-op if a Pending twin exists
await runner.query.claimJob({ id }); // status → Running