mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
perf(gateway): defer scheduled service imports
This commit is contained in:
@@ -2,10 +2,13 @@ import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { isVitestRuntimeEnv } from "../infra/env.js";
|
||||
import { startHeartbeatRunner, type HeartbeatRunner } from "../infra/heartbeat-runner.js";
|
||||
import type { PluginMetadataRegistryView } from "../plugins/plugin-metadata-snapshot.types.js";
|
||||
import type { ChannelHealthMonitor } from "./channel-health-monitor.js";
|
||||
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
|
||||
import { isGatewayModelPricingEnabled } from "./model-pricing-config.js";
|
||||
import type { startGatewayMaintenanceTimers } from "./server-maintenance.js";
|
||||
export {
|
||||
startGatewayChannelHealthMonitor,
|
||||
startGatewayRuntimeServices,
|
||||
type GatewayChannelManager,
|
||||
} from "./server-runtime-startup-services.js";
|
||||
|
||||
type GatewayRuntimeServiceLogger = {
|
||||
child: (name: string) => {
|
||||
@@ -22,10 +25,6 @@ export type GatewayMaintenanceHandles = NonNullable<
|
||||
Awaited<ReturnType<typeof startGatewayMaintenanceTimers>>
|
||||
>;
|
||||
|
||||
export type GatewayChannelManager = Parameters<
|
||||
typeof startChannelHealthMonitor
|
||||
>[0]["channelManager"];
|
||||
|
||||
function createNoopHeartbeatRunner(): HeartbeatRunner {
|
||||
return {
|
||||
stop: () => {},
|
||||
@@ -33,26 +32,6 @@ function createNoopHeartbeatRunner(): HeartbeatRunner {
|
||||
};
|
||||
}
|
||||
|
||||
export function startGatewayChannelHealthMonitor(params: {
|
||||
cfg: OpenClawConfig;
|
||||
channelManager: GatewayChannelManager;
|
||||
}): ChannelHealthMonitor | null {
|
||||
const healthCheckMinutes = params.cfg.gateway?.channelHealthCheckMinutes;
|
||||
if (healthCheckMinutes === 0) {
|
||||
return null;
|
||||
}
|
||||
const staleEventThresholdMinutes = params.cfg.gateway?.channelStaleEventThresholdMinutes;
|
||||
const maxRestartsPerHour = params.cfg.gateway?.channelMaxRestartsPerHour;
|
||||
return startChannelHealthMonitor({
|
||||
channelManager: params.channelManager,
|
||||
checkIntervalMs: (healthCheckMinutes ?? 5) * 60_000,
|
||||
...(staleEventThresholdMinutes != null && {
|
||||
staleEventThresholdMs: staleEventThresholdMinutes * 60_000,
|
||||
}),
|
||||
...(maxRestartsPerHour != null && { maxRestartsPerHour }),
|
||||
});
|
||||
}
|
||||
|
||||
export function startGatewayCronWithLogging(params: {
|
||||
cron: { start: () => Promise<void> };
|
||||
logCron: { error: (message: string) => void };
|
||||
@@ -220,28 +199,6 @@ function startGatewayModelPricingRefreshOnDemand(params: {
|
||||
};
|
||||
}
|
||||
|
||||
export function startGatewayRuntimeServices(params: {
|
||||
minimalTestGateway: boolean;
|
||||
cfgAtStart: OpenClawConfig;
|
||||
channelManager: GatewayChannelManager;
|
||||
log: GatewayRuntimeServiceLogger;
|
||||
}): {
|
||||
heartbeatRunner: HeartbeatRunner;
|
||||
channelHealthMonitor: ChannelHealthMonitor | null;
|
||||
stopModelPricingRefresh: () => void;
|
||||
} {
|
||||
const channelHealthMonitor = startGatewayChannelHealthMonitor({
|
||||
cfg: params.cfgAtStart,
|
||||
channelManager: params.channelManager,
|
||||
});
|
||||
|
||||
return {
|
||||
heartbeatRunner: createNoopHeartbeatRunner(),
|
||||
channelHealthMonitor,
|
||||
stopModelPricingRefresh: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
export function activateGatewayScheduledServices(params: {
|
||||
minimalTestGateway: boolean;
|
||||
cfgAtStart: OpenClawConfig;
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { ChannelHealthMonitor } from "./channel-health-monitor.js";
|
||||
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
|
||||
|
||||
type GatewayRuntimeServiceLogger = {
|
||||
child: (name: string) => {
|
||||
info: (message: string) => void;
|
||||
warn: (message: string) => void;
|
||||
error: (message: string) => void;
|
||||
};
|
||||
error: (message: string) => void;
|
||||
};
|
||||
|
||||
export type GatewayChannelManager = Parameters<
|
||||
typeof startChannelHealthMonitor
|
||||
>[0]["channelManager"];
|
||||
|
||||
function createNoopHeartbeatRunner() {
|
||||
return {
|
||||
stop: () => {},
|
||||
updateConfig: (_cfg: OpenClawConfig) => {},
|
||||
};
|
||||
}
|
||||
|
||||
export function startGatewayChannelHealthMonitor(params: {
|
||||
cfg: OpenClawConfig;
|
||||
channelManager: GatewayChannelManager;
|
||||
}): ChannelHealthMonitor | null {
|
||||
const healthCheckMinutes = params.cfg.gateway?.channelHealthCheckMinutes;
|
||||
if (healthCheckMinutes === 0) {
|
||||
return null;
|
||||
}
|
||||
const staleEventThresholdMinutes = params.cfg.gateway?.channelStaleEventThresholdMinutes;
|
||||
const maxRestartsPerHour = params.cfg.gateway?.channelMaxRestartsPerHour;
|
||||
return startChannelHealthMonitor({
|
||||
channelManager: params.channelManager,
|
||||
checkIntervalMs: (healthCheckMinutes ?? 5) * 60_000,
|
||||
...(staleEventThresholdMinutes != null && {
|
||||
staleEventThresholdMs: staleEventThresholdMinutes * 60_000,
|
||||
}),
|
||||
...(maxRestartsPerHour != null && { maxRestartsPerHour }),
|
||||
});
|
||||
}
|
||||
|
||||
export function startGatewayRuntimeServices(params: {
|
||||
minimalTestGateway: boolean;
|
||||
cfgAtStart: OpenClawConfig;
|
||||
channelManager: GatewayChannelManager;
|
||||
log: GatewayRuntimeServiceLogger;
|
||||
}): {
|
||||
heartbeatRunner: ReturnType<typeof createNoopHeartbeatRunner>;
|
||||
channelHealthMonitor: ChannelHealthMonitor | null;
|
||||
stopModelPricingRefresh: () => void;
|
||||
} {
|
||||
const channelHealthMonitor = startGatewayChannelHealthMonitor({
|
||||
cfg: params.cfgAtStart,
|
||||
channelManager: params.channelManager,
|
||||
});
|
||||
|
||||
return {
|
||||
heartbeatRunner: createNoopHeartbeatRunner(),
|
||||
channelHealthMonitor,
|
||||
stopModelPricingRefresh: () => {},
|
||||
};
|
||||
}
|
||||
+31
-19
@@ -1114,14 +1114,13 @@ export async function startGatewayServer(
|
||||
getActiveTaskCount = earlyRuntime.getActiveTaskCount;
|
||||
runtimeState.skillsChangeUnsub = earlyRuntime.skillsChangeUnsub;
|
||||
|
||||
const [{ startGatewayEventSubscriptions }, gatewayRuntimeServices] = await startupTrace.measure(
|
||||
"runtime.post-early-imports",
|
||||
() =>
|
||||
const [{ startGatewayEventSubscriptions }, { startGatewayRuntimeServices }] =
|
||||
await startupTrace.measure("runtime.post-early-imports", () =>
|
||||
Promise.all([
|
||||
import("./server-runtime-subscriptions.js"),
|
||||
import("./server-runtime-services.js"),
|
||||
import("./server-runtime-startup-services.js"),
|
||||
]),
|
||||
);
|
||||
);
|
||||
const runtimeSubscriptions = await startupTrace.measure("runtime.subscriptions", () =>
|
||||
startGatewayEventSubscriptions({
|
||||
broadcast,
|
||||
@@ -1138,7 +1137,7 @@ export async function startGatewayServer(
|
||||
Object.assign(runtimeState, runtimeSubscriptions);
|
||||
|
||||
const runtimeServices = await startupTrace.measure("runtime.services", () =>
|
||||
gatewayRuntimeServices.startGatewayRuntimeServices({
|
||||
startGatewayRuntimeServices({
|
||||
minimalTestGateway,
|
||||
cfgAtStart,
|
||||
channelManager,
|
||||
@@ -1516,6 +1515,13 @@ export async function startGatewayServer(
|
||||
const sessionDeliveryRecoveryMaxEnqueuedAt = Date.now();
|
||||
let postAttachRuntimeReturned = false;
|
||||
let scheduledServicesActivated = false;
|
||||
let scheduledServicesModulePromise: Promise<
|
||||
typeof import("./server-runtime-services.js")
|
||||
> | null = null;
|
||||
const loadScheduledServicesModule = () => {
|
||||
scheduledServicesModulePromise ??= import("./server-runtime-services.js");
|
||||
return scheduledServicesModulePromise;
|
||||
};
|
||||
const activateScheduledServicesWhenReady = () => {
|
||||
if (
|
||||
closePreludeStarted ||
|
||||
@@ -1525,20 +1531,25 @@ export async function startGatewayServer(
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const activated = gatewayRuntimeServices.activateGatewayScheduledServices({
|
||||
minimalTestGateway,
|
||||
cfgAtStart,
|
||||
deps,
|
||||
sessionDeliveryRecoveryMaxEnqueuedAt,
|
||||
cron: runtimeState.cronState.cron,
|
||||
startCron: false,
|
||||
logCron,
|
||||
log,
|
||||
pluginLookUpTable,
|
||||
});
|
||||
scheduledServicesActivated = true;
|
||||
runtimeState.heartbeatRunner = activated.heartbeatRunner;
|
||||
runtimeState.stopModelPricingRefresh = activated.stopModelPricingRefresh;
|
||||
void loadScheduledServicesModule().then((gatewayRuntimeServices) => {
|
||||
if (closePreludeStarted) {
|
||||
return;
|
||||
}
|
||||
const activated = gatewayRuntimeServices.activateGatewayScheduledServices({
|
||||
minimalTestGateway,
|
||||
cfgAtStart,
|
||||
deps,
|
||||
sessionDeliveryRecoveryMaxEnqueuedAt,
|
||||
cron: runtimeState.cronState.cron,
|
||||
startCron: false,
|
||||
logCron,
|
||||
log,
|
||||
pluginLookUpTable,
|
||||
});
|
||||
runtimeState.heartbeatRunner = activated.heartbeatRunner;
|
||||
runtimeState.stopModelPricingRefresh = activated.stopModelPricingRefresh;
|
||||
});
|
||||
};
|
||||
({
|
||||
stopGatewayUpdateCheck: runtimeState.stopGatewayUpdateCheck,
|
||||
@@ -1693,6 +1704,7 @@ export async function startGatewayServer(
|
||||
log.warn(`gateway: failed to promote config last-known-good backup: ${String(err)}`);
|
||||
});
|
||||
if (!minimalTestGateway) {
|
||||
const gatewayRuntimeServices = await loadScheduledServicesModule();
|
||||
postReadyMaintenanceTimer = gatewayRuntimeServices.scheduleGatewayPostReadyMaintenance({
|
||||
delayMs: POST_READY_MAINTENANCE_DELAY_MS,
|
||||
isClosing: () => closePreludeStarted,
|
||||
|
||||
Reference in New Issue
Block a user