From be3c271c9c88368a87bc7fc18622b294485c0485 Mon Sep 17 00:00:00 2001 From: Jiho Andrew Lee Date: Tue, 28 Apr 2026 00:20:00 +0900 Subject: [PATCH] refactor(podcast): inject server shutdown context into podcast service Pass the server root context (ctx) to NewPodcastService so that background download goroutines are tied to the server lifecycle and will be cancelled on shutdown, matching the pattern used by scanner.New. Signed-off-by: ji-ho lee --- cmd/wire_gen.go | 2 +- core/podcasts/podcasts.go | 15 +++++++-------- core/podcasts/podcasts_test.go | 2 +- server/subsonic/e2e/e2e_suite_test.go | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index f8b1265d5..43562da08 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -109,7 +109,7 @@ func CreateSubsonicAPIRouter(ctx context.Context) *subsonic.Router { playbackServer := playback.GetInstance(dataStore) lyricsLyrics := lyrics.NewLyrics(dataStore, manager) transcodeDecider := stream.NewTranscodeDecider(dataStore, fFmpeg) - podcastService := podcasts.NewPodcastService(dataStore, fFmpeg, broker) + podcastService := podcasts.NewPodcastService(ctx, dataStore, fFmpeg, broker) sonicSonic := sonic.New(dataStore, manager, matcherMatcher) router := subsonic.New(dataStore, artworkArtwork, mediaStreamer, archiver, players, provider, modelScanner, broker, playlistsPlaylists, playTracker, share, playbackServer, metricsMetrics, lyricsLyrics, transcodeDecider, podcastService, sonicSonic) return router diff --git a/core/podcasts/podcasts.go b/core/podcasts/podcasts.go index 8737e9f7f..8ca0c6d82 100644 --- a/core/podcasts/podcasts.go +++ b/core/podcasts/podcasts.go @@ -31,13 +31,14 @@ type Podcasts interface { } type podcastService struct { - ds model.DataStore - ff ffmpeg.FFmpeg - broker events.Broker + rootCtx context.Context + ds model.DataStore + ff ffmpeg.FFmpeg + broker events.Broker } -func NewPodcastService(ds model.DataStore, ff ffmpeg.FFmpeg, broker events.Broker) Podcasts { - return &podcastService{ds: ds, ff: ff, broker: broker} +func NewPodcastService(rootCtx context.Context, ds model.DataStore, ff ffmpeg.FFmpeg, broker events.Broker) Podcasts { + return &podcastService{rootCtx: rootCtx, ds: ds, ff: ff, broker: broker} } // podcastLibraryID returns the ID of the podcast virtual library, @@ -153,9 +154,7 @@ func (s *podcastService) DownloadEpisode(ctx context.Context, id string) error { return err } - // Use context.Background() so the download is not cancelled when the HTTP - // request completes. TODO: tie to server shutdown context for graceful termination. - go s.doDownload(context.Background(), ep, ch) + go s.doDownload(s.rootCtx, ep, ch) return nil } diff --git a/core/podcasts/podcasts_test.go b/core/podcasts/podcasts_test.go index 7226e80a6..48dad79cd 100644 --- a/core/podcasts/podcasts_test.go +++ b/core/podcasts/podcasts_test.go @@ -50,7 +50,7 @@ var _ = Describe("PodcastService", func() { DeferCleanup(mockServer.Close) conf.Server.DataFolder = GinkgoT().TempDir() - svc = podcasts.NewPodcastService(ds, nil, nil) + svc = podcasts.NewPodcastService(ctx, ds, nil, nil) }) Describe("AddChannel", func() { diff --git a/server/subsonic/e2e/e2e_suite_test.go b/server/subsonic/e2e/e2e_suite_test.go index 666636920..9879fa181 100644 --- a/server/subsonic/e2e/e2e_suite_test.go +++ b/server/subsonic/e2e/e2e_suite_test.go @@ -431,7 +431,7 @@ func setupTestDB() { metrics.NewNoopInstance(), lyrics.NewLyrics(ds, nil), decider, - podcasts.NewPodcastService(ds, ffmpeg.New(), events.NoopBroker()), + podcasts.NewPodcastService(context.Background(), ds, ffmpeg.New(), events.NoopBroker()), nil, ) }