perf: reduce desktop quit risk polling
Refresh quit risk only when quitting Use in-process status for Electron local server Avoid repeated scheduled task status scans
This commit is contained in:
+20
-21
@@ -128,7 +128,6 @@ const state = {
|
|||||||
quitConfirmed: false,
|
quitConfirmed: false,
|
||||||
quitConfirmationPending: false,
|
quitConfirmationPending: false,
|
||||||
installingUpdate: false,
|
installingUpdate: false,
|
||||||
quitRiskPollerStarted: false,
|
|
||||||
pendingUpdate: null,
|
pendingUpdate: null,
|
||||||
unreachableHosts: new Set(),
|
unreachableHosts: new Set(),
|
||||||
windowCounter: 1,
|
windowCounter: 1,
|
||||||
@@ -138,7 +137,6 @@ const state = {
|
|||||||
sshLogs: new Map(),
|
sshLogs: new Map(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const QUIT_RISK_POLL_INTERVAL_MS = 5_000;
|
|
||||||
const quitRisk = {
|
const quitRisk = {
|
||||||
hasActiveTunnel: false,
|
hasActiveTunnel: false,
|
||||||
hasRunningScheduledTasks: false,
|
hasRunningScheduledTasks: false,
|
||||||
@@ -206,6 +204,8 @@ const performConfirmedQuit = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const requestQuitWithConfirmation = async () => {
|
const requestQuitWithConfirmation = async () => {
|
||||||
|
await refreshQuitRiskFlags();
|
||||||
|
|
||||||
if (!shouldRequireQuitConfirmation()) {
|
if (!shouldRequireQuitConfirmation()) {
|
||||||
performConfirmedQuit();
|
performConfirmedQuit();
|
||||||
return;
|
return;
|
||||||
@@ -247,6 +247,24 @@ const requestQuitWithConfirmation = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const refreshQuitRiskFlags = async () => {
|
const refreshQuitRiskFlags = async () => {
|
||||||
|
if (state.serverHandle && typeof state.serverHandle.getQuitRiskStatus === 'function') {
|
||||||
|
try {
|
||||||
|
const status = await state.serverHandle.getQuitRiskStatus();
|
||||||
|
const scheduled = status?.scheduledTasks;
|
||||||
|
if (scheduled && typeof scheduled === 'object') {
|
||||||
|
const enabledCount = Number(scheduled.enabledScheduledTasksCount ?? 0);
|
||||||
|
const runningCount = Number(scheduled.runningScheduledTasksCount ?? 0);
|
||||||
|
quitRisk.enabledScheduledTasksCount = Number.isFinite(enabledCount) ? enabledCount : 0;
|
||||||
|
quitRisk.runningScheduledTasksCount = Number.isFinite(runningCount) ? runningCount : 0;
|
||||||
|
quitRisk.hasEnabledScheduledTasks = Boolean(scheduled.hasEnabledScheduledTasks) || quitRisk.enabledScheduledTasksCount > 0;
|
||||||
|
quitRisk.hasRunningScheduledTasks = Boolean(scheduled.hasRunningScheduledTasks) || quitRisk.runningScheduledTasksCount > 0;
|
||||||
|
}
|
||||||
|
quitRisk.hasActiveTunnel = Boolean(status?.tunnel?.active);
|
||||||
|
return;
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const base = typeof state.sidecarUrl === 'string' ? state.sidecarUrl.trim().replace(/\/$/, '') : '';
|
const base = typeof state.sidecarUrl === 'string' ? state.sidecarUrl.trim().replace(/\/$/, '') : '';
|
||||||
if (!base) return;
|
if (!base) return;
|
||||||
|
|
||||||
@@ -279,24 +297,6 @@ const refreshQuitRiskFlags = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const startQuitRiskPoller = () => {
|
|
||||||
if (process.platform !== 'darwin') return;
|
|
||||||
if (state.quitRiskPollerStarted) return;
|
|
||||||
state.quitRiskPollerStarted = true;
|
|
||||||
|
|
||||||
const loop = async () => {
|
|
||||||
while (!state.quitConfirmed && !state.quitRequested) {
|
|
||||||
await refreshQuitRiskFlags();
|
|
||||||
if (state.quitConfirmed || state.quitRequested) break;
|
|
||||||
await new Promise((resolve) => {
|
|
||||||
const timer = setTimeout(resolve, QUIT_RISK_POLL_INTERVAL_MS);
|
|
||||||
if (typeof timer?.unref === 'function') timer.unref();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
void loop();
|
|
||||||
};
|
|
||||||
|
|
||||||
const settingsFilePath = () => {
|
const settingsFilePath = () => {
|
||||||
if (typeof process.env.OPENCHAMBER_DATA_DIR === 'string' && process.env.OPENCHAMBER_DATA_DIR.trim()) {
|
if (typeof process.env.OPENCHAMBER_DATA_DIR === 'string' && process.env.OPENCHAMBER_DATA_DIR.trim()) {
|
||||||
return path.join(process.env.OPENCHAMBER_DATA_DIR.trim(), 'settings.json');
|
return path.join(process.env.OPENCHAMBER_DATA_DIR.trim(), 'settings.json');
|
||||||
@@ -2399,7 +2399,6 @@ app.whenReady().then(async () => {
|
|||||||
|
|
||||||
const { initialUrl, localOrigin, bootOutcome } = await resolveInitialUrl();
|
const { initialUrl, localOrigin, bootOutcome } = await resolveInitialUrl();
|
||||||
await activateMainWindow(initialUrl, localOrigin, bootOutcome);
|
await activateMainWindow(initialUrl, localOrigin, bootOutcome);
|
||||||
startQuitRiskPoller();
|
|
||||||
|
|
||||||
// Notify renderer on OS wake-from-sleep so the SSE event pipeline can
|
// Notify renderer on OS wake-from-sleep so the SSE event pipeline can
|
||||||
// reconnect immediately instead of waiting for the heartbeat watchdog.
|
// reconnect immediately instead of waiting for the heartbeat watchdog.
|
||||||
|
|||||||
@@ -1233,6 +1233,12 @@ async function main(options = {}) {
|
|||||||
getPort: () => tunnelRuntimeContext.getActivePort(),
|
getPort: () => tunnelRuntimeContext.getActivePort(),
|
||||||
getOpenCodePort: () => openCodePort,
|
getOpenCodePort: () => openCodePort,
|
||||||
getTunnelUrl: () => tunnelService.getPublicUrl(),
|
getTunnelUrl: () => tunnelService.getPublicUrl(),
|
||||||
|
getQuitRiskStatus: () => ({
|
||||||
|
tunnel: {
|
||||||
|
active: Boolean(tunnelService.getPublicUrl()),
|
||||||
|
},
|
||||||
|
scheduledTasks: scheduledTasksRuntime.getStatus(),
|
||||||
|
}),
|
||||||
isReady: () => isOpenCodeReady,
|
isReady: () => isOpenCodeReady,
|
||||||
restartOpenCode: () => restartOpenCode(),
|
restartOpenCode: () => restartOpenCode(),
|
||||||
stop: (shutdownOptions = {}) =>
|
stop: (shutdownOptions = {}) =>
|
||||||
|
|||||||
@@ -156,6 +156,10 @@ export const registerScheduledTaskRoutes = (app, dependencies) => {
|
|||||||
|
|
||||||
app.get('/api/openchamber/scheduled-tasks/status', async (_req, res) => {
|
app.get('/api/openchamber/scheduled-tasks/status', async (_req, res) => {
|
||||||
try {
|
try {
|
||||||
|
if (typeof scheduledTasksRuntime.getStatus === 'function') {
|
||||||
|
return res.json(scheduledTasksRuntime.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
const settings = await readSettingsFromDiskMigrated();
|
const settings = await readSettingsFromDiskMigrated();
|
||||||
const projects = sanitizeProjects(settings?.projects || []);
|
const projects = sanitizeProjects(settings?.projects || []);
|
||||||
|
|
||||||
|
|||||||
@@ -739,11 +739,31 @@ export const createScheduledTasksRuntime = (deps) => {
|
|||||||
queue.length = 0;
|
queue.length = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getStatus = () => {
|
||||||
|
let enabledCount = 0;
|
||||||
|
for (const taskMap of tasksByProject.values()) {
|
||||||
|
for (const task of taskMap.values()) {
|
||||||
|
if (task?.enabled) {
|
||||||
|
enabledCount += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const runningCount = runningTaskKeys.size;
|
||||||
|
return {
|
||||||
|
hasEnabledScheduledTasks: enabledCount > 0,
|
||||||
|
hasRunningScheduledTasks: runningCount > 0,
|
||||||
|
enabledScheduledTasksCount: enabledCount,
|
||||||
|
runningScheduledTasksCount: runningCount,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
start,
|
start,
|
||||||
stop,
|
stop,
|
||||||
syncAllProjects,
|
syncAllProjects,
|
||||||
syncProject,
|
syncProject,
|
||||||
runNow,
|
runNow,
|
||||||
|
getStatus,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user