services: lazy start services / on demand services

services are now stopped when no app is using them.

on start up, services are always created and run. they are later
stopped when unused. it's this way to facilitate the upgrade code
path. the database meta files have to be upgraded even if no app is using them.
the other hook to stop unused services is at the end of an app task.

maybe mail container is a candidate for the future where all sending is no-op.
But give this is rare, it's not implemented.
This commit is contained in:
Girish Ramakrishnan
2026-03-07 22:30:43 +05:30
parent 99c55cb22f
commit 4bc0f44789
6 changed files with 77 additions and 9 deletions
+10 -3
View File
@@ -47,11 +47,13 @@ async function drain() {
scheduler.suspendAppJobs(appId);
// background
let taskError = null, taskResult = null;
tasks.startTask(taskId, Object.assign(options, { logFile }))
.then(async (result) => await safe(onFinished(null, result), { debug }))
.catch(async (error) => await safe(onFinished(error), { debug }))
.then((result) => { taskResult = result; })
.catch((error) => { taskError = error; })
.finally(async () => {
delete gActiveTasks[appId];
await safe(onFinished(taskError, taskResult), { debug }); // hasPendingTasks() can now return false
await locks.release(`${locks.TYPE_APP_TASK_PREFIX}${appId}`);
await locks.releaseByTaskId(taskId);
scheduler.resumeAppJobs(appId);
@@ -89,7 +91,12 @@ function scheduleTask(appId, taskId, options, onFinished) {
if (gStarted && !gDrainTimerId) gDrainTimerId = setTimeout(drain, DRAIN_TIMER_SECS);
}
function hasPendingTasks() {
return Object.keys(gActiveTasks).length > 0 || gPendingTasks.length > 0;
}
export default {
start,
scheduleTask
scheduleTask,
hasPendingTasks
};