diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-09 21:42:48 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-09 21:42:48 +0300 |
| commit | d96c86cfeef342d17cc88e1cb3cc75bdf060339e (patch) | |
| tree | b96fc2765fa0efa516557073045b18c84674f54a | |
| parent | 914092f4d519aa7107439d48b882d149ddff1118 (diff) | |
more on this
| -rw-r--r-- | cmd/player/main.go | 16 | ||||
| -rw-r--r-- | internal/service/gc.go | 5 | ||||
| -rw-r--r-- | internal/service/podcast.go | 1 | ||||
| -rw-r--r-- | internal/service/scan.go | 7 |
4 files changed, 24 insertions, 5 deletions
diff --git a/cmd/player/main.go b/cmd/player/main.go index 94cad3e..b043de5 100644 --- a/cmd/player/main.go +++ b/cmd/player/main.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "os/signal" + "runtime/debug" "syscall" "time" @@ -80,6 +81,12 @@ func buildLogger(logLevel string) *slog.Logger { return slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: level})) } +func recoverBackgroundWorkerPanic(logger *slog.Logger, worker string) { + if r := recover(); r != nil { + logger.Error("background worker panic", "worker", worker, "panic", r, "stack", string(debug.Stack())) + } +} + // wireDeps constructs the core service layer dependencies. func wireDeps(cfg *internal.Config, store repository.Store, logger *slog.Logger, appCtx context.Context) *appDeps { clk := clock.RealClock{} @@ -130,9 +137,12 @@ func startBackgroundWorkers(deps *appDeps) { for { select { case <-ticker.C: - if err := deps.podcastSvc.CheckFeeds(context.Background()); err != nil { - deps.logger.Error("podcast feed check failed", "err", err) - } + func() { + defer recoverBackgroundWorkerPanic(deps.logger, "podcast checker") + if err := deps.podcastSvc.CheckFeeds(context.Background()); err != nil { + deps.logger.Error("podcast feed check failed", "err", err) + } + }() case <-deps.appCtx.Done(): return } diff --git a/internal/service/gc.go b/internal/service/gc.go index 8ff3204..f7ea396 100644 --- a/internal/service/gc.go +++ b/internal/service/gc.go @@ -70,7 +70,10 @@ func (w *GCWorker) Start() { for { select { case <-tickCh: - w.run(w.ctx) + func() { + defer recoverWorkerPanic(w.logger, "gc") + w.run(w.ctx) + }() w.notifyRunDone() case <-w.stopCh: return diff --git a/internal/service/podcast.go b/internal/service/podcast.go index ad5e22b..269df68 100644 --- a/internal/service/podcast.go +++ b/internal/service/podcast.go @@ -656,6 +656,7 @@ func (s *podcastService) CheckFeeds(ctx context.Context) error { wg.Add(1) go func(f model.PodcastFeed) { defer wg.Done() + defer recoverWorkerPanic(s.logger, "podcast feed check") if err := s.checkFeed(ctx, f); err != nil { s.logger.Warn("podcast feed check failed", "feed_id", f.ID, "feed_url", f.FeedURL, "err", err) } else { diff --git a/internal/service/scan.go b/internal/service/scan.go index d2cc5bb..1bd7fda 100644 --- a/internal/service/scan.go +++ b/internal/service/scan.go @@ -59,6 +59,12 @@ func (s *scanService) TriggerRescan(ctx context.Context) error { go func() { defer cancel() + defer s.notifyDone() + defer func() { + if err := recoverWorkerPanic(s.logger, "rescan"); err != nil { + progress.Done(err) + } + }() err := s.scanner.Scan(scanCtx, s.mediaRoot, progress) if err == nil { err = scanCtx.Err() @@ -70,7 +76,6 @@ func (s *scanService) TriggerRescan(ctx context.Context) error { progress.Done(nil) s.logger.Info("rescan completed") } - s.notifyDone() }() return nil } |
