You've already forked agentic-coding-workflow
feat(jobs): Module wiring + WorkerOptions.OnDeadLetter hook
This commit is contained in:
@@ -2,6 +2,7 @@ package jobs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"sync"
|
||||
@@ -19,6 +20,12 @@ type WorkerOptions struct {
|
||||
Backoff []time.Duration
|
||||
Clock clock.Clock
|
||||
Log *slog.Logger
|
||||
// OnDeadLetter, if non-nil, is invoked once after a job is moved to dead-letter
|
||||
// (either because IsPermanent(err) or attempts exhausted). The hook runs in
|
||||
// the worker goroutine; panics are recovered and logged but do not stop the
|
||||
// worker. Use this for fallback admin notifications when external delivery
|
||||
// fails permanently.
|
||||
OnDeadLetter func(ctx context.Context, job Job, err error)
|
||||
}
|
||||
|
||||
// Worker pulls leased jobs from the repository, dispatches them to handlers,
|
||||
@@ -88,6 +95,7 @@ func (w *Worker) execute(ctx context.Context, job Job) {
|
||||
w.opts.Log.Error("job.dead_letter_write_failed", "id", job.ID, "err", derr.Error())
|
||||
}
|
||||
w.opts.Log.Error("job.dead_letter", "id", job.ID, "type", job.Type, "reason", "unknown_type")
|
||||
w.fireOnDeadLetter(ctx, job, errors.New("unknown job type: "+string(job.Type)))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -110,6 +118,7 @@ func (w *Worker) execute(ctx context.Context, job Job) {
|
||||
}
|
||||
w.opts.Log.Error("job.dead_letter",
|
||||
"id", job.ID, "type", job.Type, "attempts", job.Attempts, "err", msg)
|
||||
w.fireOnDeadLetter(ctx, job, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -148,6 +157,19 @@ func backoffFor(seq []time.Duration, attempt int) time.Duration {
|
||||
return seq[idx]
|
||||
}
|
||||
|
||||
// fireOnDeadLetter invokes opts.OnDeadLetter, if set, recovering any panics.
|
||||
func (w *Worker) fireOnDeadLetter(ctx context.Context, job Job, err error) {
|
||||
if w.opts.OnDeadLetter == nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
w.opts.Log.Error("job.dead_letter_hook_panic", "id", job.ID, "panic", r)
|
||||
}
|
||||
}()
|
||||
w.opts.OnDeadLetter(ctx, job, err)
|
||||
}
|
||||
|
||||
func truncate(s string, n int) string {
|
||||
if len(s) <= n {
|
||||
return s
|
||||
|
||||
Reference in New Issue
Block a user