refactor: unify restart gating and update availability sync

This commit is contained in:
Peter Steinberger
2026-02-19 10:00:27 +01:00
parent 18179fc2c1
commit b4dbe03298
25 changed files with 288 additions and 41 deletions

7
src/gateway/events.ts Normal file
View File

@@ -0,0 +1,7 @@
import type { UpdateAvailable } from "../infra/update-startup.js";
export const GATEWAY_EVENT_UPDATE_AVAILABLE = "update.available" as const;
export type GatewayUpdateAvailableEventPayload = {
updateAvailable: UpdateAvailable | null;
};

View File

@@ -1,4 +1,5 @@
import { listChannelPlugins } from "../channels/plugins/index.js";
import { GATEWAY_EVENT_UPDATE_AVAILABLE } from "./events.js";
const BASE_METHODS = [
"health",
@@ -117,4 +118,5 @@ export const GATEWAY_EVENTS = [
"voicewake.changed",
"exec.approval.requested",
"exec.approval.resolved",
GATEWAY_EVENT_UPDATE_AVAILABLE,
];

View File

@@ -2,6 +2,7 @@ import { getActiveEmbeddedRunCount } from "../agents/pi-embedded-runner/runs.js"
import { getTotalPendingReplies } from "../auto-reply/reply/dispatcher-registry.js";
import type { CliDeps } from "../cli/deps.js";
import { resolveAgentMaxConcurrent, resolveSubagentMaxConcurrent } from "../config/agent-limits.js";
import { isRestartEnabled } from "../config/commands.js";
import type { loadConfig } from "../config/config.js";
import { startGmailWatcherWithLogs } from "../hooks/gmail-watcher-lifecycle.js";
import { stopGmailWatcher } from "../hooks/gmail-watcher.js";
@@ -48,7 +49,7 @@ export function createGatewayReloadHandlers(params: {
plan: GatewayReloadPlan,
nextConfig: ReturnType<typeof loadConfig>,
) => {
setGatewaySigusr1RestartPolicy({ allowExternal: nextConfig.commands?.restart === true });
setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(nextConfig) });
const state = params.getState();
const nextState = { ...state };
@@ -138,7 +139,7 @@ export function createGatewayReloadHandlers(params: {
plan: GatewayReloadPlan,
nextConfig: ReturnType<typeof loadConfig>,
) => {
setGatewaySigusr1RestartPolicy({ allowExternal: nextConfig.commands?.restart === true });
setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(nextConfig) });
const reasons = plan.restartReasons.length
? plan.restartReasons.join(", ")
: plan.changedPaths.join(", ");

View File

@@ -8,6 +8,7 @@ import type { CanvasHostServer } from "../canvas-host/server.js";
import { type ChannelId, listChannelPlugins } from "../channels/plugins/index.js";
import { formatCliCommand } from "../cli/command-format.js";
import { createDefaultDeps } from "../cli/deps.js";
import { isRestartEnabled } from "../config/commands.js";
import {
CONFIG_PATH,
isNixMode,
@@ -49,6 +50,10 @@ import { createAuthRateLimiter, type AuthRateLimiter } from "./auth-rate-limit.j
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
import { startGatewayConfigReloader } from "./config-reload.js";
import type { ControlUiRootState } from "./control-ui.js";
import {
GATEWAY_EVENT_UPDATE_AVAILABLE,
type GatewayUpdateAvailableEventPayload,
} from "./events.js";
import { ExecApprovalManager } from "./exec-approval-manager.js";
import { NodeRegistry } from "./node-registry.js";
import type { startBrowserControlServerIfEnabled } from "./server-browser.js";
@@ -252,7 +257,7 @@ export async function startGatewayServer(
if (diagnosticsEnabled) {
startDiagnosticHeartbeat();
}
setGatewaySigusr1RestartPolicy({ allowExternal: cfgAtStart.commands?.restart === true });
setGatewaySigusr1RestartPolicy({ allowExternal: isRestartEnabled(cfgAtStart) });
setPreRestartDeferralCheck(
() => getTotalQueueSize() + getTotalPendingReplies() + getActiveEmbeddedRunCount(),
);
@@ -628,7 +633,15 @@ export async function startGatewayServer(
isNixMode,
});
if (!minimalTestGateway) {
scheduleGatewayUpdateCheck({ cfg: cfgAtStart, log, isNixMode });
scheduleGatewayUpdateCheck({
cfg: cfgAtStart,
log,
isNixMode,
onUpdateAvailableChange: (updateAvailable) => {
const payload: GatewayUpdateAvailableEventPayload = { updateAvailable };
broadcast(GATEWAY_EVENT_UPDATE_AVAILABLE, payload, { dropIfSlow: true });
},
});
}
const tailscaleCleanup = minimalTestGateway
? null