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:
fallenbagel
2026-02-07 01:38:21 +05:00
committed by GitHub
parent a0a784b976
commit faa2c0a005
9 changed files with 109 additions and 7 deletions

View File

@@ -5,9 +5,10 @@ import PageTitle from '@app/components/Common/PageTitle';
import Tooltip from '@app/components/Common/Tooltip';
import RequestItem from '@app/components/RequestList/RequestItem';
import { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';
import { useUser } from '@app/hooks/useUser';
import { Permission, useUser } from '@app/hooks/useUser';
import globalMessages from '@app/i18n/globalMessages';
import defineMessages from '@app/utils/defineMessages';
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
import {
ArrowDownIcon,
ArrowUpIcon,
@@ -30,6 +31,8 @@ const messages = defineMessages('components.RequestList', {
sortAdded: 'Most Recent',
sortModified: 'Last Modified',
sortDirection: 'Toggle Sort Direction',
unableToConnect:
'Unable to connect to {services}. Some information may be unavailable.',
});
enum Filter {
@@ -56,7 +59,7 @@ const RequestList = () => {
const { user } = useUser({
id: Number(router.query.userId),
});
const { user: currentUser } = useUser();
const { user: currentUser, hasPermission } = useUser();
const [currentFilter, setCurrentFilter] = useState<Filter>(Filter.PENDING);
const [currentSort, setCurrentSort] = useState<Sort>('added');
const [currentMediaType, setCurrentMediaType] = useState<string>('all');
@@ -288,6 +291,25 @@ const RequestList = () => {
</div>
</div>
</div>
{data.serviceErrors &&
(data.serviceErrors.radarr.length > 0 ||
data.serviceErrors.sonarr.length > 0) &&
(hasPermission(Permission.MANAGE_REQUESTS) ||
hasPermission(Permission.REQUEST_ADVANCED)) && (
<div className="service-error-banner">
<ExclamationTriangleIcon className="h-5 w-5 flex-shrink-0" />
<span>
{intl.formatMessage(messages.unableToConnect, {
services: [
...data.serviceErrors.radarr.map((s) => s.name),
...data.serviceErrors.sonarr.map((s) => s.name),
].join(', '),
})}
</span>
</div>
)}
{data.results.map((request) => {
return (
<div className="py-2" key={`request-list-${request.id}`}>