From 6b08d43e6cb26149b8a99569d6e5a8d11437212f Mon Sep 17 00:00:00 2001 From: Mondo Diaz Date: Tue, 5 May 2026 09:38:08 -0500 Subject: [PATCH] reload services after server CRUD so creds aren't stale The /servers POST/PUT/DELETE handlers updated the database but left the running media-server services holding their original URL/api_key in memory, so e.g. rotating Sappho's API key in the UI looked successful but the WebSocket and HTTP polls kept presenting the old (revoked) key until the container was restarted manually. Call restartMonitoring() after each mutation to tear down WebSockets and reinit services from the updated DB rows. Co-Authored-By: Claude Opus 4.7 (1M context) --- backend/src/routes/api.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/routes/api.js b/backend/src/routes/api.js index 8322f5b..4674b80 100644 --- a/backend/src/routes/api.js +++ b/backend/src/routes/api.js @@ -1,6 +1,6 @@ import express from 'express'; import db from '../database/init.js'; -import { embyService, plexService, audiobookshelfService, sapphoService, jellyfinService, seerrService, getServerHealthStatus } from '../services/monitor.js'; +import { embyService, plexService, audiobookshelfService, sapphoService, jellyfinService, seerrService, getServerHealthStatus, restartMonitoring } from '../services/monitor.js'; import { getJobs, runJob, updateJob } from '../services/jobs.js'; import { requireAdmin } from '../middleware/auth.js'; import { encrypt, decrypt } from '../utils/crypto.js'; @@ -1324,6 +1324,8 @@ router.post('/servers', (req, res) => { `).run(id, type, name, url, encryptedApiKey, enabled !== false ? 1 : 0, now, now); const server = db.prepare('SELECT * FROM servers WHERE id = ?').get(id); + // Reload services so the new server is monitored without a container restart + restartMonitoring(); // Return with masked API key res.json({ success: true, data: { ...server, api_key: '***' } }); } catch (error) { @@ -1362,6 +1364,9 @@ router.put('/servers/:id', (req, res) => { ); const server = db.prepare('SELECT * FROM servers WHERE id = ?').get(id); + // Reload services so updates to URL/key/enabled flag take effect immediately + // instead of the running services holding stale credentials in memory. + restartMonitoring(); // Return with masked API key res.json({ success: true, data: { ...server, api_key: '***' } }); } catch (error) { @@ -1380,6 +1385,8 @@ router.delete('/servers/:id', (req, res) => { } db.prepare('DELETE FROM servers WHERE id = ?').run(id); + // Reload services so the deleted server's WebSockets/cron entries are torn down. + restartMonitoring(); res.json({ success: true, message: 'Server deleted' }); } catch (error) { res.status(500).json({ success: false, error: error.message });