- HeartbeatArgs + HeartbeatWorker (logs slog.Info on each tick) - OrphanCleanupArgs + OrphanCleanupWorker (S3 delete then DB delete loop) - NewOrphanCleanupWorker constructor with pool + FileStorer injection - SlogErrorHandler implementing river.ErrorHandler (HandleError + HandlePanic) - fileQuerier interface for test injection without real DB - Unit tests: 7 tests pass (pure mock-based, no DB required) - go build ./... exits 0
39 lines
892 B
Go
39 lines
892 B
Go
package jobs
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
|
|
"github.com/riverqueue/river"
|
|
"github.com/riverqueue/river/rivertype"
|
|
)
|
|
|
|
// SlogErrorHandler logs job errors and panics via the structured slog logger.
|
|
// Returning nil from HandleError and HandlePanic instructs river to follow its
|
|
// default retry schedule.
|
|
type SlogErrorHandler struct{}
|
|
|
|
func (*SlogErrorHandler) HandleError(
|
|
ctx context.Context, job *rivertype.JobRow, err error,
|
|
) *river.ErrorHandlerResult {
|
|
slog.Error("job error",
|
|
"job_id", job.ID,
|
|
"job_kind", job.Kind,
|
|
"attempt", job.Attempt,
|
|
"max_attempts", job.MaxAttempts,
|
|
"err", err,
|
|
)
|
|
return nil
|
|
}
|
|
|
|
func (*SlogErrorHandler) HandlePanic(
|
|
ctx context.Context, job *rivertype.JobRow, panicVal any, trace string,
|
|
) *river.ErrorHandlerResult {
|
|
slog.Error("job panic",
|
|
"job_id", job.ID,
|
|
"job_kind", job.Kind,
|
|
"panic", panicVal,
|
|
"trace", trace,
|
|
)
|
|
return nil
|
|
}
|