fix: rTorrent null-safety, configurable SAB_HISTORY_LIMIT, lastError visibility (#68)
Build and Push Docker Image / build (push) Successful in 59s
Docs Check / Markdown lint (push) Failing after 1m45s
Licence Check / Licence compatibility and copyright header verification (push) Successful in 2m7s
CI / Security audit (push) Successful in 2m33s
Docs Check / Mermaid diagram parse check (push) Successful in 2m55s
CI / Swagger Validation & Coverage (push) Successful in 3m19s
CI / Tests & coverage (push) Successful in 3m29s

- RTorrentClient: guard d.multicall2 returning non-array, per-row try/catch,
  explicit Number()/String() coercions, _extractArrInfo null-safe
- RTorrentClient.getClientStatus: coerce rates through Number.isFinite
- SABnzbdClient: history limit now reads SAB_HISTORY_LIMIT env var (default 10)
- DownloadClient: added _recordLastError, _clearLastError, getLastError on base
- All four clients call _recordLastError on failure, _clearLastError on success
- DownloadClientRegistry.getAllClientStatuses: includes lastError in result
- GET /api/status/status: exposes downloadClients[] array with per-client lastError
- Tests: RTorrentClient null-safety + lastError, SABnzbd history limit + lastError,
  downloadClients.test expectation updated for new lastError field
This commit is contained in:
2026-05-28 16:22:11 +01:00
parent 3d49c926dc
commit 6fa9c79a7d
11 changed files with 284 additions and 22 deletions
+11 -1
View File
@@ -7,6 +7,7 @@ const { getLastPollTimings, POLLING_ENABLED } = require('../utils/poller');
const { getSonarrInstances, getRadarrInstances, getOmbiInstances } = require('../utils/config');
const { getGlobalWebhookMetrics } = require('../utils/cache');
const { checkWebhookConfigured, checkOmbiWebhookConfigured, aggregateMetrics } = require('../services/WebhookStatus');
const downloadClientRegistry = require('../utils/downloadClients');
/**
* @openapi
@@ -165,7 +166,16 @@ router.get('/', requireAuth, async (req, res) => {
sonarr: aggregateMetrics(sonarrMetrics, sonarrWebhookConfigured),
radarr: aggregateMetrics(radarrMetrics, radarrWebhookConfigured),
ombi: aggregateMetrics(ombiMetrics, ombiWebhookConfigured)
}
},
// Per-download-client health summary including any lastError captured
// since the last successful call. Lets the admin status panel surface
// transient failures (auth expiry, RPC blips, etc.) without log scraping.
downloadClients: downloadClientRegistry.getAllClients().map(c => ({
instanceId: c.getInstanceId(),
instanceName: c.name,
clientType: c.getClientType(),
lastError: typeof c.getLastError === 'function' ? c.getLastError() : null
}))
});
} catch (err) {
res.status(500).json({ error: 'Failed to get status', details: err.message });