feat: make background polling disablable with on-demand fallback
- Set POLL_INTERVAL=0, off, false, or disabled to disable background polling - When disabled, data is fetched on-demand when a user opens the dashboard - On-demand results cached for 30s so other users benefit from fresh data - A user with a faster refresh rate keeps the cache warm for everyone - When polling is enabled, behaviour is unchanged (default 5s)
This commit is contained in:
@@ -54,7 +54,7 @@ const radarrRoutes = require('./routes/radarr');
|
|||||||
const embyRoutes = require('./routes/emby');
|
const embyRoutes = require('./routes/emby');
|
||||||
const dashboardRoutes = require('./routes/dashboard');
|
const dashboardRoutes = require('./routes/dashboard');
|
||||||
const authRoutes = require('./routes/auth');
|
const authRoutes = require('./routes/auth');
|
||||||
const { startPoller, POLL_INTERVAL } = require('./utils/poller');
|
const { startPoller, POLL_INTERVAL, POLLING_ENABLED } = require('./utils/poller');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 3001;
|
const PORT = process.env.PORT || 3001;
|
||||||
@@ -80,7 +80,7 @@ app.listen(PORT, () => {
|
|||||||
console.log(` sofarr - Your Downloads Dashboard`);
|
console.log(` sofarr - Your Downloads Dashboard`);
|
||||||
console.log(` Server running on port ${PORT}`);
|
console.log(` Server running on port ${PORT}`);
|
||||||
console.log(` Log level: ${process.env.LOG_LEVEL || 'info'}`);
|
console.log(` Log level: ${process.env.LOG_LEVEL || 'info'}`);
|
||||||
console.log(` Poll interval: ${POLL_INTERVAL}ms`);
|
console.log(` Polling: ${POLLING_ENABLED ? POLL_INTERVAL + 'ms' : 'disabled (on-demand)'}`);
|
||||||
console.log(`=================================`);
|
console.log(`=================================`);
|
||||||
startPoller();
|
startPoller();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const router = express.Router();
|
|||||||
|
|
||||||
const { mapTorrentToDownload } = require('../utils/qbittorrent');
|
const { mapTorrentToDownload } = require('../utils/qbittorrent');
|
||||||
const cache = require('../utils/cache');
|
const cache = require('../utils/cache');
|
||||||
|
const { pollAllServices, POLLING_ENABLED } = require('../utils/poller');
|
||||||
|
|
||||||
const EMBY_URL = process.env.EMBY_URL;
|
const EMBY_URL = process.env.EMBY_URL;
|
||||||
const EMBY_API_KEY = process.env.EMBY_API_KEY;
|
const EMBY_API_KEY = process.env.EMBY_API_KEY;
|
||||||
@@ -105,7 +106,14 @@ router.get('/user-downloads', async (req, res) => {
|
|||||||
const showAll = isAdmin && req.query.showAll === 'true';
|
const showAll = isAdmin && req.query.showAll === 'true';
|
||||||
console.log(`[Dashboard] Serving downloads for user: ${user.name} (${username}), isAdmin: ${isAdmin}, showAll: ${showAll}`);
|
console.log(`[Dashboard] Serving downloads for user: ${user.name} (${username}), isAdmin: ${isAdmin}, showAll: ${showAll}`);
|
||||||
|
|
||||||
// Read all data from poller cache
|
// When polling is disabled, fetch on-demand if cache has expired
|
||||||
|
// The fetched data is cached (30s TTL) so subsequent requests from any user reuse it
|
||||||
|
if (!POLLING_ENABLED && !cache.get('poll:sab-queue')) {
|
||||||
|
console.log(`[Dashboard] Cache expired and polling disabled, fetching on-demand...`);
|
||||||
|
await pollAllServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read all data from cache
|
||||||
const sabQueueData = cache.get('poll:sab-queue') || { slots: [] };
|
const sabQueueData = cache.get('poll:sab-queue') || { slots: [] };
|
||||||
const sabHistoryData = cache.get('poll:sab-history') || { slots: [] };
|
const sabHistoryData = cache.get('poll:sab-history') || { slots: [] };
|
||||||
const sonarrTagsResults = cache.get('poll:sonarr-tags') || [];
|
const sonarrTagsResults = cache.get('poll:sonarr-tags') || [];
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ const {
|
|||||||
getRadarrInstances
|
getRadarrInstances
|
||||||
} = require('./config');
|
} = require('./config');
|
||||||
|
|
||||||
const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL, 10) || 5000;
|
const rawPollInterval = (process.env.POLL_INTERVAL || '').toLowerCase();
|
||||||
|
const POLL_INTERVAL = (rawPollInterval === 'off' || rawPollInterval === 'false' || rawPollInterval === 'disabled')
|
||||||
|
? 0
|
||||||
|
: (parseInt(process.env.POLL_INTERVAL, 10) || 5000);
|
||||||
|
const POLLING_ENABLED = POLL_INTERVAL > 0;
|
||||||
|
|
||||||
let polling = false;
|
let polling = false;
|
||||||
|
|
||||||
@@ -125,8 +129,9 @@ async function pollAllServices() {
|
|||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Aggregate and store in cache (TTL slightly longer than poll interval to avoid gaps)
|
// When polling is active, TTL is 3x interval to avoid gaps between polls
|
||||||
const cacheTTL = POLL_INTERVAL * 3;
|
// When polling is disabled (on-demand), use 30s so data refreshes on next request after expiry
|
||||||
|
const cacheTTL = POLLING_ENABLED ? POLL_INTERVAL * 3 : 30000;
|
||||||
|
|
||||||
// SABnzbd
|
// SABnzbd
|
||||||
const firstSabQueue = sabQueues[0] && sabQueues[0].data && sabQueues[0].data.queue;
|
const firstSabQueue = sabQueues[0] && sabQueues[0].data && sabQueues[0].data.queue;
|
||||||
@@ -182,6 +187,10 @@ async function pollAllServices() {
|
|||||||
let intervalHandle = null;
|
let intervalHandle = null;
|
||||||
|
|
||||||
function startPoller() {
|
function startPoller() {
|
||||||
|
if (!POLLING_ENABLED) {
|
||||||
|
console.log(`[Poller] Background polling disabled (POLL_INTERVAL=${process.env.POLL_INTERVAL || 'not set'}). Data will be fetched on-demand.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.log(`[Poller] Starting background poller (interval: ${POLL_INTERVAL}ms)`);
|
console.log(`[Poller] Starting background poller (interval: ${POLL_INTERVAL}ms)`);
|
||||||
// Run immediately, then on interval
|
// Run immediately, then on interval
|
||||||
pollAllServices();
|
pollAllServices();
|
||||||
@@ -196,4 +205,4 @@ function stopPoller() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { startPoller, stopPoller, POLL_INTERVAL };
|
module.exports = { startPoller, stopPoller, pollAllServices, POLL_INTERVAL, POLLING_ENABLED };
|
||||||
|
|||||||
Reference in New Issue
Block a user