Relay Hook
Emit typed webhook events at every Dispatch lifecycle point using relay_hook.
The relay_hook package bridges Dispatch lifecycle events to Relay for webhook delivery. When registered as a Dispatch extension, it emits a typed webhook event at every job, workflow, cron, and shutdown lifecycle point.
Setup
import (
"github.com/xraph/relay"
"github.com/xraph/dispatch/relay_hook"
"github.com/xraph/relay/store/memory"
)
// Create a Relay instance.
r, _ := relay.New(relay.WithStore(memory.New()))
// Register the event types Dispatch will emit.
relay_hook.RegisterAll(ctx, r)
// Create the hook extension.
hook := relay_hook.New(r)
// Register with the engine.
eng := engine.Build(d,
engine.WithExtension(hook),
)Emitted event types
| Event type | Lifecycle point |
|---|---|
dispatch.job.enqueued | Job accepted into queue |
dispatch.job.started | Worker begins execution |
dispatch.job.completed | Job finishes successfully |
dispatch.job.failed | Job fails terminally |
dispatch.job.retrying | Job fails, scheduled for retry |
dispatch.job.dlq | Job moved to DLQ |
dispatch.workflow.started | Workflow run begins |
dispatch.workflow.step.completed | Workflow step completes |
dispatch.workflow.step.failed | Workflow step fails |
dispatch.workflow.completed | Workflow run completes |
dispatch.workflow.failed | Workflow run fails |
dispatch.cron.fired | Cron entry fires |
dispatch.shutdown | Dispatcher shuts down |
Filtering events
Restrict which events are emitted:
hook := relay_hook.New(r,
relay_hook.WithEvents(
relay_hook.EventJobCompleted,
relay_hook.EventJobFailed,
relay_hook.EventJobDLQ,
relay_hook.EventWorkflowFailed,
),
)Event payload
Each webhook event carries a JSON payload with the full entity at the time of the lifecycle event. For example, dispatch.job.completed includes:
{
"job_id": "job_01h2xcejqtf2nbrexx3vqjhp41",
"name": "send_email",
"queue": "default",
"elapsed_ms": 142,
"completed_at": "2025-01-15T09:00:00Z"
}Tenant routing
Webhook events are routed to Relay endpoints matching the job's ScopeOrgID as the TenantID. If ScopeOrgID is empty, events are routed to a global tenant.