mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 04:47:03 -06:00
docs: document gateway shutdown session helpers
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// Gateway shutdown and restart close orchestration.
|
||||
// Coordinates hooks, drains, sockets, sidecars, plugins, and runtime cleanup.
|
||||
import type { Server as HttpServer } from "node:http";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import type { WebSocketServer } from "ws";
|
||||
@@ -18,8 +20,6 @@ import {
|
||||
import type { ChatRunEntry, ChatRunState } from "./server-chat-state.js";
|
||||
import type { GatewayPostReadySidecarHandle } from "./server-startup-post-attach.js";
|
||||
|
||||
// Gateway shutdown/restart close orchestration with bounded drain and cleanup steps.
|
||||
|
||||
const shutdownLog = createSubsystemLogger("gateway/shutdown");
|
||||
const GATEWAY_SHUTDOWN_HOOK_TIMEOUT_MS = 5_000;
|
||||
const GATEWAY_PRE_RESTART_HOOK_TIMEOUT_MS = 10_000;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Gateway Control UI root resolver.
|
||||
// Finds configured, bundled, or source-built UI assets during startup.
|
||||
import path from "node:path";
|
||||
import {
|
||||
ensureControlUiAssetsBuilt,
|
||||
@@ -8,9 +10,6 @@ import {
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import type { ControlUiRootState } from "./control-ui.js";
|
||||
|
||||
// Control UI root resolution prefers explicit config, then bundled/proven
|
||||
// assets. Missing bundled assets trigger an async build attempt without blocking
|
||||
// gateway startup.
|
||||
function startControlUiAssetsBuild(params: {
|
||||
gatewayRuntime: RuntimeEnv;
|
||||
log: { warn: (message: string) => void };
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Gateway cron lazy loader.
|
||||
// Defers scheduler startup until cron is touched by runtime or API handlers.
|
||||
import type { CliDeps } from "../cli/deps.types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import type { CronServiceContract } from "../cron/service-contract.js";
|
||||
import { resolveCronJobsStorePath } from "../cron/store.js";
|
||||
import type { GatewayCronState } from "./server-cron.js";
|
||||
|
||||
// Gateway cron is loaded lazily so startup/tests that never touch cron do not
|
||||
// materialize scheduler loops or bundled plugin runtime.
|
||||
type LazyGatewayCronParams = {
|
||||
cfg: OpenClawConfig;
|
||||
deps: CliDeps;
|
||||
@@ -29,6 +29,8 @@ export function createLazyGatewayCronState(params: LazyGatewayCronParams): Gatew
|
||||
if (loaded) {
|
||||
return loaded;
|
||||
}
|
||||
// Share the same import promise across concurrent API calls so only one
|
||||
// scheduler instance is built for a Gateway process.
|
||||
loading ??= import("./server-cron.js").then(({ buildGatewayCronService }) => {
|
||||
loaded = {
|
||||
state: buildGatewayCronService(params),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Gateway maintenance timers.
|
||||
// Starts periodic health, dedupe, abort, and media cleanup loops.
|
||||
import { isFutureDateTimestampMs } from "@openclaw/normalization-core/number-coercion";
|
||||
import type { HealthSummary } from "../commands/health.js";
|
||||
import { sweepStaleRunContexts } from "../infra/agent-events.js";
|
||||
@@ -128,6 +130,8 @@ export function startGatewayMaintenanceTimers(params: {
|
||||
return isFutureDateTimestampMs(expiresAtMs, { nowMs: now });
|
||||
};
|
||||
const isActiveRunDedupeKey = (key: string, dedupeEntry: DedupeEntry) => {
|
||||
// Keep idempotency records for active runs so retries cannot create
|
||||
// duplicate chat/agent work while a command is still draining.
|
||||
if (!key.startsWith("agent:") && !key.startsWith("chat:")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Gateway session event broadcaster.
|
||||
// Projects transcript and lifecycle updates to websocket subscribers.
|
||||
import { asPositiveSafeInteger } from "@openclaw/normalization-core/number-coercion";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
|
||||
@@ -20,10 +22,6 @@ import {
|
||||
type GatewaySessionRow,
|
||||
} from "./session-utils.js";
|
||||
|
||||
// Session event broadcasting bridges transcript/lifecycle stores to live
|
||||
// Gateway websocket subscribers. Message updates go to session-specific
|
||||
// subscribers plus broad session listeners; non-display messages still trigger
|
||||
// sessions.changed so lists refresh.
|
||||
type SessionEventSubscribers = Pick<SessionEventSubscriberRegistry, "getAll">;
|
||||
type SessionMessageSubscribers = Pick<SessionMessageSubscriberRegistry, "get">;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Gateway shared-auth generation enforcement.
|
||||
// Disconnects clients when config writes invalidate shared credentials.
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveGatewayReloadSettings } from "./config-reload-settings.js";
|
||||
|
||||
// Tracks shared Gateway auth generations across config writes and reload modes.
|
||||
|
||||
/** Gateway client subset relevant to shared auth generation enforcement. */
|
||||
export type SharedGatewayAuthClient = {
|
||||
usesSharedGatewayAuth?: boolean;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Filesystem session transcript helpers.
|
||||
// Resolves, archives, and cleans up transcript files owned by Gateway sessions.
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
@@ -118,6 +120,8 @@ export function resolveSessionTranscriptCandidates(
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the legacy global sessions directory as a final candidate so tagged
|
||||
// upgrades can still find transcripts created before per-agent paths.
|
||||
const home = resolveRequiredHomeDir(process.env, os.homedir);
|
||||
const legacyDir = path.join(home, ".openclaw", "sessions");
|
||||
pushCandidate(() => resolveSessionTranscriptPathInDir(sessionId, legacyDir));
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Session transcript key resolver.
|
||||
// Maps transcript file paths back to Gateway session keys for live broadcasts.
|
||||
import { getRuntimeConfig } from "../config/io.js";
|
||||
import type { SessionEntry } from "../config/sessions/types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
@@ -38,10 +40,12 @@ function sessionKeyMatchesTranscriptPath(params: {
|
||||
).some((candidate) => resolveTranscriptPathForComparison(candidate) === params.targetPath);
|
||||
}
|
||||
|
||||
/** Clears the transcript path lookup cache for isolated tests. */
|
||||
export function clearSessionTranscriptKeyCacheForTests(): void {
|
||||
TRANSCRIPT_SESSION_KEY_CACHE.clear();
|
||||
}
|
||||
|
||||
/** Resolve the most likely Gateway session key for a transcript file path. */
|
||||
export function resolveSessionKeyForTranscriptFile(sessionFile: string): string | undefined {
|
||||
const targetPath = resolveTranscriptPathForComparison(sessionFile);
|
||||
if (!targetPath) {
|
||||
@@ -81,6 +85,8 @@ export function resolveSessionKeyForTranscriptFile(sessionFile: string): string
|
||||
}
|
||||
|
||||
if (matchingEntries.length > 0) {
|
||||
// Multiple keys can point at copied/forked transcript paths. Prefer the
|
||||
// freshest unambiguous session ID group; ties stay unresolved.
|
||||
const matchesBySessionId = new Map<string, Array<[string, SessionEntry]>>();
|
||||
for (const entry of matchingEntries) {
|
||||
const sessionId = entry[1].sessionId;
|
||||
|
||||
Reference in New Issue
Block a user