From e9c04a1fa6498b232a24e9948220be17b2707809 Mon Sep 17 00:00:00 2001 From: ji-ho 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 94caa5bee..9d0b68fb3 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -106,7 +106,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 90fdaa9a4..cd39b4429 100644 --- a/server/subsonic/e2e/e2e_suite_test.go +++ b/server/subsonic/e2e/e2e_suite_test.go @@ -427,7 +427,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, ) }