Job Queue
Durable background processing backed by PostgreSQL. Jobs survive Core restarts and are automatically retried if a worker crashes.
How It Works
When you enqueue a job, it is immediately persisted in PostgreSQL. The scheduler picks it up and dispatches it to the appropriate backend worker via the onJob lifecycle hook.
If the worker crashes or takes too long, the job automatically becomes available again for retry. Handlers should be idempotent as a best practice, since a job may be delivered more than once.
Job Lifecycle
| Status | Meaning |
|---|---|
| Queued | Waiting to be picked up by the scheduler. |
| Processing | Dispatched to a backend worker. |
| Completed | Handler returned successfully. Job archived. |
| Failed | Handler threw an error. Job removed. |
Using Studio
View job status in the Operations panel. The panel shows queued and completed jobs with their payloads and results.
Using Code
Enqueue a Job
POST /api/v1/apps/{appId}/jobs
{
"payload": { "type": "email", "to": "user@example.com" }
}
Returns { "msg_id": 42 }. The job is persisted immediately and picked up as soon as a worker is available.
Handle Jobs in Your Backend
Use the onJob lifecycle hook in serve() to handle jobs:
serve({}, {
onJob: async (payload) => {
if (payload.type === "email") {
await sendEmail(payload.to);
return { delivered: true };
}
},
});
Return a value to mark the job as completed. Throw to mark it as failed.
List Jobs
GET /api/v1/apps/{appId}/jobs
Returns active jobs in the queue. Add ?archived=true to list completed jobs.
Jobs and crons share the same queue and the same onJob handler. For recurring scheduled work, see Scheduled Jobs (Crons).