From f22dd0d1f68851f8cf1ce029a1d67f1d6a39833d Mon Sep 17 00:00:00 2001 From: Gronod Date: Tue, 19 May 2026 21:40:53 +0100 Subject: [PATCH] fix(downloads): Fix SABnzbd/qBittorrent collision and webhook metrics 1. Fixed download client collision: - SABnzbd client with id 'i3omb' was being overwritten by qBittorrent - Now uses unique key ':' like the arr retrievers 2. Fixed webhook metrics showing 0: - instanceName from webhooks is generic ('Sonarr', 'Radarr') - Not the configured instance name ('i3omb') - Now updates metrics for ALL instances of that type --- server/routes/webhook.js | 20 ++++++++++++++------ server/utils/downloadClients.js | 5 +++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/server/routes/webhook.js b/server/routes/webhook.js index 9bf5797..483c27c 100644 --- a/server/routes/webhook.js +++ b/server/routes/webhook.js @@ -247,10 +247,14 @@ router.post('/sonarr', webhookLimiter, (req, res) => { logToFile(`[Webhook] Sonarr payload: ${JSON.stringify(req.body)}`); // Phase 5.1: update webhook metrics for polling optimization + // Note: instanceName from webhook is often generic (e.g., "Sonarr"), not the configured name + // Update metrics for all Sonarr instances since we can't reliably match const sonarrInstances = getSonarrInstances(); - const instance = sonarrInstances.find(i => i.name === instanceName); - if (instance) { - cache.updateWebhookMetrics(instance.url); + if (sonarrInstances.length > 0) { + for (const inst of sonarrInstances) { + cache.updateWebhookMetrics(inst.url); + } + logToFile(`[Webhook] Updated metrics for ${sonarrInstances.length} Sonarr instance(s)`); } // Phase 2: background cache refresh + SSE broadcast (fire-and-forget) @@ -296,10 +300,14 @@ router.post('/radarr', webhookLimiter, (req, res) => { logToFile(`[Webhook] Radarr payload: ${JSON.stringify(req.body)}`); // Phase 5.1: update webhook metrics for polling optimization + // Note: instanceName from webhook is often generic (e.g., "Radarr"), not the configured name + // Update metrics for all Radarr instances since we can't reliably match const radarrInstances = getRadarrInstances(); - const instance = radarrInstances.find(i => i.name === instanceName); - if (instance) { - cache.updateWebhookMetrics(instance.url); + if (radarrInstances.length > 0) { + for (const inst of radarrInstances) { + cache.updateWebhookMetrics(inst.url); + } + logToFile(`[Webhook] Updated metrics for ${radarrInstances.length} Radarr instance(s)`); } // Phase 2: background cache refresh + SSE broadcast (fire-and-forget) diff --git a/server/utils/downloadClients.js b/server/utils/downloadClients.js index 60ea6ed..50a7785 100644 --- a/server/utils/downloadClients.js +++ b/server/utils/downloadClients.js @@ -63,8 +63,9 @@ class DownloadClientRegistry { } const client = new ClientClass(config); - this.clients.set(config.id, client); - logToFile(`[DownloadClientRegistry] Created ${config.type} client: ${config.name} (${config.id})`); + const uniqueKey = `${config.type}:${config.id}`; + this.clients.set(uniqueKey, client); + logToFile(`[DownloadClientRegistry] Created ${config.type} client: ${config.name} (${uniqueKey})`); } catch (error) { logToFile(`[DownloadClientRegistry] Failed to create client ${config.id}: ${error.message}`); }