diff --git a/src/app/pipelines/RecommendationPipeline.ts b/src/app/pipelines/RecommendationPipeline.ts index c73c9dc..a315cea 100644 --- a/src/app/pipelines/RecommendationPipeline.ts +++ b/src/app/pipelines/RecommendationPipeline.ts @@ -90,8 +90,12 @@ export class RecommendationPipeline extends LlmPipeline { if (!this.options.radarr) return; for (const rec of recommendations) { - const movie = await this.options.radarr.lookup(rec.tmdbId); - await this.options.radarr.addMovie(movie); + try { + const movie = await this.options.radarr.lookup(rec.tmdbId); + await this.options.radarr.addMovie(movie); + } catch (err) { + this.logger.error({ err, tmdbId: rec.tmdbId, title: rec.title }, 'Radarr auto-request failed'); + } } } diff --git a/test/app/pipelines/RecommendationPipeline.test.ts b/test/app/pipelines/RecommendationPipeline.test.ts index 6c88464..24d334d 100644 --- a/test/app/pipelines/RecommendationPipeline.test.ts +++ b/test/app/pipelines/RecommendationPipeline.test.ts @@ -215,6 +215,46 @@ describe('RecommendationPipeline.autoRequest', () => { await expect(pipeline.autoRequest([{ title: 'Dune', year: 2021, tmdbId: 1, reason: 'r' }])).resolves.toBeUndefined(); }); + + it('logs and continues when one recommendation fails, instead of aborting the rest', async () => { + const radarr = { + lookup: vi + .fn() + .mockRejectedValueOnce(new Error('radarr down')) + .mockResolvedValueOnce({ + title: 'Arrival', + tmdbId: 2, + qualityProfileId: 1, + rootFolderPath: '/movies', + monitored: true, + addOptions: { searchForMovie: true }, + }), + addMovie: vi.fn().mockResolvedValue(undefined), + } as unknown as RadarrClient; + const logger = { error: vi.fn() } as unknown as Logger; + + const pipeline = new RecommendationPipeline(makeTracer(), logger, { + jellyfin: {} as JellyfinClient, + tmdb: {} as TmdbClient, + radarr, + tool: {} as MovieRecommenderTool, + searchTool: {} as MovieSearchTool, + minRatedMovies: 1, + maxRetry: 0, + }); + + await pipeline.autoRequest([ + { title: 'Dune', year: 2021, tmdbId: 1, reason: 'r1' }, + { title: 'Arrival', year: 2016, tmdbId: 2, reason: 'r2' }, + ]); + + expect(logger.error).toHaveBeenCalledWith( + expect.objectContaining({ tmdbId: 1, title: 'Dune' }), + 'Radarr auto-request failed' + ); + expect(radarr.lookup).toHaveBeenCalledTimes(2); + expect(radarr.addMovie).toHaveBeenCalledTimes(1); + }); }); describe('RecommendationPipeline.searchAsync', () => {