Skip to content

Events Reference

OJS defines a standard event vocabulary for job lifecycle events. These events enable real-time monitoring, webhook integrations, audit logging, and workflow coordination.

Every lifecycle event follows a consistent structure:

{
"event": "job.completed",
"timestamp": "2026-02-12T10:30:02.789Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"attempt": 1,
"duration_ms": 1333,
"result": { "delivered": true }
}
}
FieldTypeDescription
eventstringEvent type from the vocabulary below
timestampstringISO 8601 / RFC 3339 timestamp
job_idstringUUIDv7 job identifier
job_typestringThe dot-namespaced job type
queuestringQueue name
dataobjectEvent-specific payload

Emitted when a job is submitted via PUSH and enters available, scheduled, or pending state.

{
"event": "job.enqueued",
"timestamp": "2026-02-12T10:30:00.123Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"state": "available",
"priority": 0
}
}

Emitted when a worker claims a job via FETCH and the job enters active state.

{
"event": "job.started",
"timestamp": "2026-02-12T10:30:01.456Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"attempt": 1,
"worker_id": "worker-abc123"
}
}

Emitted when a job is successfully acknowledged via ACK and enters completed state.

{
"event": "job.completed",
"timestamp": "2026-02-12T10:30:02.789Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"attempt": 1,
"duration_ms": 1333,
"result": { "delivered": true }
}
}

Emitted when a job handler fails via FAIL. The job may enter retryable or discarded state depending on the retry policy.

{
"event": "job.failed",
"timestamp": "2026-02-12T10:30:02.000Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"attempt": 1,
"duration_ms": 567,
"error": {
"type": "SmtpConnectionError",
"message": "Connection refused"
},
"next_state": "retryable",
"retry_at": "2026-02-12T10:30:03.000Z"
}
}

Emitted when a retryable job’s backoff period expires and it moves back to available.

{
"event": "job.retrying",
"timestamp": "2026-02-12T10:30:03.000Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"attempt": 1,
"next_attempt": 2
}
}

Emitted when a job enters the dead letter queue after exhausting all retry attempts.

{
"event": "job.discarded",
"timestamp": "2026-02-12T10:35:00.000Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"attempt": 3,
"total_attempts": 3,
"error": {
"type": "SmtpConnectionError",
"message": "Connection refused"
}
}
}

Emitted when a job is cancelled via CANCEL.

{
"event": "job.cancelled",
"timestamp": "2026-02-12T10:31:00.000Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "email.send",
"queue": "email",
"data": {
"previous_state": "available",
"cancelled_by": "api"
}
}

Emitted when a scheduled job’s time arrives and it transitions from scheduled to available.

{
"event": "job.scheduled",
"timestamp": "2026-02-12T10:30:00.000Z",
"job_id": "019414d4-8b2e-7c3a-b5d1-f0e2a3b4c5d6",
"job_type": "notification.send_digest",
"queue": "notifications",
"data": {
"scheduled_at": "2026-02-12T10:30:00.000Z"
}
}

Emitted when a worker registers with the server.

{
"event": "worker.registered",
"timestamp": "2026-02-12T10:00:00.000Z",
"data": {
"worker_id": "worker-abc123",
"queues": ["default", "email"],
"concurrency": 10
}
}

Emitted on each worker heartbeat.

Emitted when a worker transitions to the quiet state (stops fetching new jobs).

Emitted when a worker shuts down.

How you subscribe to events depends on your backend:

Redis backend: Uses Redis Pub/Sub channels. Subscribe to ojs:events for all events, or ojs:events:job.completed for a specific event type.

PostgreSQL backend: Uses LISTEN/NOTIFY. Listen on the ojs_events channel.

HTTP webhooks: Some backends support webhook registration for push-based event delivery. Check the conformance manifest for webhook support.

All OJS SDKs provide an event emitter for subscribing to events on the client and worker:

// JavaScript SDK
const worker = new OJSWorker({ url: 'http://localhost:8080' });
worker.events.on('job:completed', (event) => {
console.log(`Job ${event.job_id} completed in ${event.data.duration_ms}ms`);
});
worker.events.on('job:failed', (event) => {
console.error(`Job ${event.job_id} failed: ${event.data.error.message}`);
});
// Go SDK
worker.OnEvent("job.completed", func(e ojs.Event) {
log.Printf("Job %s completed", e.JobID)
})