mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-19 17:11:42 -06:00
144 lines
4.8 KiB
TypeScript
144 lines
4.8 KiB
TypeScript
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 { ChannelHealthMonitor } from "./channel-health-monitor.js";
|
|
import { startChannelHealthMonitor } from "./channel-health-monitor.js";
|
|
import { startGatewayModelPricingRefresh } from "./model-pricing-cache.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(): HeartbeatRunner {
|
|
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 startGatewayCronWithLogging(params: {
|
|
cron: { start: () => Promise<void> };
|
|
logCron: { error: (message: string) => void };
|
|
}): void {
|
|
void params.cron.start().catch((err) => params.logCron.error(`failed to start: ${String(err)}`));
|
|
}
|
|
|
|
function recoverPendingOutboundDeliveries(params: {
|
|
cfg: OpenClawConfig;
|
|
log: GatewayRuntimeServiceLogger;
|
|
}): void {
|
|
void (async () => {
|
|
const { recoverPendingDeliveries } = await import("../infra/outbound/delivery-queue.js");
|
|
const { deliverOutboundPayloads } = await import("../infra/outbound/deliver.js");
|
|
const logRecovery = params.log.child("delivery-recovery");
|
|
await recoverPendingDeliveries({
|
|
deliver: deliverOutboundPayloads,
|
|
log: logRecovery,
|
|
cfg: params.cfg,
|
|
});
|
|
})().catch((err) => params.log.error(`Delivery recovery failed: ${String(err)}`));
|
|
}
|
|
|
|
function recoverPendingSessionDeliveries(params: {
|
|
deps: import("../cli/deps.types.js").CliDeps;
|
|
log: GatewayRuntimeServiceLogger;
|
|
maxEnqueuedAt: number;
|
|
}): void {
|
|
const timer = setTimeout(() => {
|
|
void (async () => {
|
|
const { recoverPendingRestartContinuationDeliveries } =
|
|
await import("./server-restart-sentinel.js");
|
|
const logRecovery = params.log.child("session-delivery-recovery");
|
|
await recoverPendingRestartContinuationDeliveries({
|
|
deps: params.deps,
|
|
log: logRecovery,
|
|
maxEnqueuedAt: params.maxEnqueuedAt,
|
|
});
|
|
})().catch((err) => params.log.error(`Session delivery recovery failed: ${String(err)}`));
|
|
}, 1_250);
|
|
timer.unref?.();
|
|
}
|
|
|
|
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:
|
|
!params.minimalTestGateway && !isVitestRuntimeEnv()
|
|
? startGatewayModelPricingRefresh({ config: params.cfgAtStart })
|
|
: () => {},
|
|
};
|
|
}
|
|
|
|
export function activateGatewayScheduledServices(params: {
|
|
minimalTestGateway: boolean;
|
|
cfgAtStart: OpenClawConfig;
|
|
deps: import("../cli/deps.types.js").CliDeps;
|
|
sessionDeliveryRecoveryMaxEnqueuedAt: number;
|
|
cron: { start: () => Promise<void> };
|
|
logCron: { error: (message: string) => void };
|
|
log: GatewayRuntimeServiceLogger;
|
|
}): { heartbeatRunner: HeartbeatRunner } {
|
|
if (params.minimalTestGateway) {
|
|
return { heartbeatRunner: createNoopHeartbeatRunner() };
|
|
}
|
|
const heartbeatRunner = startHeartbeatRunner({ cfg: params.cfgAtStart });
|
|
startGatewayCronWithLogging({
|
|
cron: params.cron,
|
|
logCron: params.logCron,
|
|
});
|
|
recoverPendingOutboundDeliveries({
|
|
cfg: params.cfgAtStart,
|
|
log: params.log,
|
|
});
|
|
recoverPendingSessionDeliveries({
|
|
deps: params.deps,
|
|
log: params.log,
|
|
maxEnqueuedAt: params.sessionDeliveryRecoveryMaxEnqueuedAt,
|
|
});
|
|
return { heartbeatRunner };
|
|
}
|