fix(servarr): add timeout to Radarr/Sonarr API requests to prevent infinite loading (#2375)
* fix(servarr): add timeout to Radarr/Sonarr API requests to prevent infinite loading Adds a 5-second timeout to all Radarr/Sonarr API requests and displays a warning banner when services are unreachable. This prevents the Recent Requests section and request list pages from hanging indefinitely when a configured service has connection issues. fix #2374 * fix(requests): only show service error banner to users with advanced permissions
This commit is contained in:
@@ -92,11 +92,13 @@ class ServarrBase<QueueItemAppendT> extends ExternalAPI {
|
||||
apiKey,
|
||||
cacheName,
|
||||
apiName,
|
||||
timeout = 5000,
|
||||
}: {
|
||||
url: string;
|
||||
apiKey: string;
|
||||
cacheName: AvailableCacheIds;
|
||||
apiName: string;
|
||||
timeout?: number;
|
||||
}) {
|
||||
super(
|
||||
url,
|
||||
@@ -105,6 +107,7 @@ class ServarrBase<QueueItemAppendT> extends ExternalAPI {
|
||||
},
|
||||
{
|
||||
nodeCache: cacheManager.getCache(cacheName).data,
|
||||
timeout,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -64,8 +64,16 @@ export interface RadarrMovie {
|
||||
}
|
||||
|
||||
class RadarrAPI extends ServarrBase<{ movieId: number }> {
|
||||
constructor({ url, apiKey }: { url: string; apiKey: string }) {
|
||||
super({ url, apiKey, cacheName: 'radarr', apiName: 'Radarr' });
|
||||
constructor({
|
||||
url,
|
||||
apiKey,
|
||||
timeout,
|
||||
}: {
|
||||
url: string;
|
||||
apiKey: string;
|
||||
timeout?: number;
|
||||
}) {
|
||||
super({ url, apiKey, cacheName: 'radarr', apiName: 'Radarr', timeout });
|
||||
}
|
||||
|
||||
public getMovies = async (): Promise<RadarrMovie[]> => {
|
||||
|
||||
@@ -111,8 +111,16 @@ class SonarrAPI extends ServarrBase<{
|
||||
episodeId: number;
|
||||
episode: EpisodeResult;
|
||||
}> {
|
||||
constructor({ url, apiKey }: { url: string; apiKey: string }) {
|
||||
super({ url, apiKey, apiName: 'Sonarr', cacheName: 'sonarr' });
|
||||
constructor({
|
||||
url,
|
||||
apiKey,
|
||||
timeout,
|
||||
}: {
|
||||
url: string;
|
||||
apiKey: string;
|
||||
timeout?: number;
|
||||
}) {
|
||||
super({ url, apiKey, apiName: 'Sonarr', cacheName: 'sonarr', timeout });
|
||||
}
|
||||
|
||||
public async getSeries(): Promise<SonarrSeries[]> {
|
||||
|
||||
@@ -7,6 +7,10 @@ export interface RequestResultsResponse extends PaginatedResponse {
|
||||
profileName?: string;
|
||||
canRemove?: boolean;
|
||||
})[];
|
||||
serviceErrors: {
|
||||
radarr: { id: number; name: string }[];
|
||||
sonarr: { id: number; name: string }[];
|
||||
};
|
||||
}
|
||||
|
||||
export type MediaRequestBody = {
|
||||
|
||||
@@ -275,6 +275,24 @@ requestRoutes.get<Record<string, unknown>, RequestResultsResponse>(
|
||||
page: Math.ceil(skip / pageSize) + 1,
|
||||
},
|
||||
results: mappedRequests,
|
||||
serviceErrors: {
|
||||
radarr: radarrServers
|
||||
.filter((s) => !s.profiles)
|
||||
.map((s) => ({
|
||||
id: s.id,
|
||||
name:
|
||||
settings.radarr.find((r) => r.id === s.id)?.name ||
|
||||
`Radarr ${s.id}`,
|
||||
})),
|
||||
sonarr: sonarrServers
|
||||
.filter((s) => !s.profiles)
|
||||
.map((s) => ({
|
||||
id: s.id,
|
||||
name:
|
||||
settings.sonarr.find((r) => r.id === s.id)?.name ||
|
||||
`Sonarr ${s.id}`,
|
||||
})),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
next({ status: 500, message: e.message });
|
||||
|
||||
Reference in New Issue
Block a user