Events
Durably provides an event system for monitoring job execution and extensibility.
Subscribing to Events
durably.on(eventType: string, listener: (event) => void): voidEvent Types
Run Events
run:trigger
Fired when a job is triggered (before worker picks it up).
durably.on('run:trigger', (event) => {
// event: {
// type: 'run:trigger',
// runId: string,
// jobName: string,
// input: unknown,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:leased
Fired when a run acquires a lease and begins execution.
durably.on('run:leased', (event) => {
// event: {
// type: 'run:leased',
// runId: string,
// jobName: string,
// input: unknown,
// leaseOwner: string,
// leaseExpiresAt: string,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:lease-renewed
Fired when a run's lease is renewed during execution.
durably.on('run:lease-renewed', (event) => {
// event: {
// type: 'run:lease-renewed',
// runId: string,
// jobName: string,
// leaseOwner: string,
// leaseExpiresAt: string,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:complete
Fired when a run completes successfully.
durably.on('run:complete', (event) => {
// event: {
// type: 'run:complete',
// runId: string,
// jobName: string,
// output: unknown,
// duration: number,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:fail
Fired when a run fails.
durably.on('run:fail', (event) => {
// event: {
// type: 'run:fail',
// runId: string,
// jobName: string,
// error: string,
// failedStepName: string,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:progress
Fired when step.progress() is called.
durably.on('run:progress', (event) => {
// event: {
// type: 'run:progress',
// runId: string,
// jobName: string,
// progress: { current: number, total?: number, message?: string },
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:cancel
Fired when a run is cancelled via cancel() API.
durably.on('run:cancel', (event) => {
// event: {
// type: 'run:cancel',
// runId: string,
// jobName: string,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})run:delete
Fired when a run is deleted via deleteRun() API.
durably.on('run:delete', (event) => {
// event: {
// type: 'run:delete',
// runId: string,
// jobName: string,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})Step Events
step:start
Fired when a step begins execution.
durably.on('step:start', (event) => {
// event: {
// type: 'step:start',
// runId: string,
// jobName: string,
// stepName: string,
// stepIndex: number,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})step:complete
Fired when a step completes successfully.
durably.on('step:complete', (event) => {
// event: {
// type: 'step:complete',
// runId: string,
// jobName: string,
// stepName: string,
// stepIndex: number,
// output: unknown,
// duration: number,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})step:fail
Fired when a step fails.
durably.on('step:fail', (event) => {
// event: {
// type: 'step:fail',
// runId: string,
// jobName: string,
// stepName: string,
// stepIndex: number,
// error: string,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})step:cancel
Fired when a step is cancelled (run was cancelled while step was executing).
durably.on('step:cancel', (event) => {
// event: {
// type: 'step:cancel',
// runId: string,
// jobName: string,
// stepName: string,
// stepIndex: number,
// labels: Record<string, string>,
// timestamp: string,
// sequence: number
// }
})Log Events
log:write
Fired when step.log methods are called.
durably.on('log:write', (event) => {
// event: {
// type: 'log:write',
// runId: string,
// jobName: string,
// labels: Record<string, string>,
// stepName: string | null,
// level: 'info' | 'warn' | 'error',
// message: string,
// data: unknown,
// timestamp: string,
// sequence: number
// }
})Worker Events
worker:error
Fired when an internal worker error occurs (e.g., lease renewal failure).
durably.on('worker:error', (event) => {
// event: {
// type: 'worker:error',
// error: string,
// context: string, // e.g., 'lease-renewal'
// runId?: string,
// timestamp: string,
// sequence: number
// }
})Synchronous Execution
Listeners run synchronously
Event listeners are called synchronously in the worker's hot path. A slow listener will block job execution and lease renewal until it returns. Keep listeners fast and non-blocking.
Do:
// Fast: queue work for later
durably.on('run:complete', (e) => {
void sendToAnalytics(e) // fire-and-forget async
})
// Fast: simple logging
durably.on('run:fail', (e) => {
console.error(`[${e.jobName}] Failed: ${e.error}`)
})Don't:
// Slow: synchronous heavy computation blocks the worker
durably.on('run:complete', (e) => {
const report = generateExpensiveReport(e) // ❌ blocks polling
fs.writeFileSync('report.json', JSON.stringify(report))
})Error Handling
Exceptions thrown in event listeners are caught and forwarded to the error handler — they do not crash the worker, abort the current run, or interrupt subsequent listeners for the same event. If a listener returns a rejected Promise (async listener), the rejection is also forwarded to onError. Use onError to catch both:
durably.onError((error, event) => {
console.error('Listener error:', error, 'during event:', event.type)
})Type Definitions
All events use a discriminated union pattern:
interface BaseEvent {
type: string
timestamp: string
sequence: number
}
type DurablyEvent =
| RunTriggerEvent
| RunLeasedEvent
| RunLeaseRenewedEvent
| RunCompleteEvent
| RunFailEvent
| RunCancelEvent
| RunProgressEvent
| StepStartEvent
| StepCompleteEvent
| StepFailEvent
| StepCancelEvent
| LogWriteEvent
| WorkerErrorEvent
// Shared data types used by events and callbacks
interface ProgressData {
current: number
total?: number
message?: string
}
interface LogData {
level: 'info' | 'warn' | 'error'
message: string
data?: unknown
stepName?: string | null
}RunProgressEvent contains a progress: ProgressData field. LogWriteEvent extends LogData with additional event fields (runId, jobName, labels, etc.).
Both ProgressData and LogData are also used as callback parameter types in TriggerAndWaitOptions.
Example
const durably = createDurably({ dialect })
// Log all events
durably.on('run:leased', (e) => {
console.log(`[${e.jobName}] Run leased: ${e.runId}`)
})
durably.on('run:complete', (e) => {
console.log(`[${e.jobName}] Run completed in ${e.duration}ms`)
})
durably.on('run:fail', (e) => {
console.error(`[${e.jobName}] Run failed: ${e.error}`)
// Send alert to monitoring service
alertService.notify({
title: `Job ${e.jobName} failed`,
message: e.error,
runId: e.runId,
})
})
durably.on('step:complete', (e) => {
console.log(` Step "${e.stepName}" completed in ${e.duration}ms`)
})
// Handle listener errors
durably.onError((error, event) => {
console.error('Event listener threw:', error)
})