























@@ -19,15 +19,49 @@ import {
1919} from "./gateway-supervisor.js";
2020import type { DiscordMonitorStatusSink } from "./status.js";
212122-const DISCORD_GATEWAY_READY_TIMEOUT_MS = 15_000;
23-const DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS = 30_000;
22+const DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS = 15_000;
23+const DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS = 30_000;
24+const MAX_DISCORD_GATEWAY_READY_TIMEOUT_MS = 120_000;
25+const DISCORD_GATEWAY_READY_TIMEOUT_ENV = "OPENCLAW_DISCORD_READY_TIMEOUT_MS";
26+const DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV = "OPENCLAW_DISCORD_RUNTIME_READY_TIMEOUT_MS";
2427const DISCORD_GATEWAY_READY_POLL_MS = 250;
2528const DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS = 5_000;
2629const DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS = 1_000;
2730const DISCORD_GATEWAY_TRANSPORT_ACTIVITY_STATUS_MIN_INTERVAL_MS = 30_000;
28312932type GatewayReadyWaitResult = "ready" | "stopped" | "timeout";
303334+function normalizeGatewayReadyTimeoutMs(value: unknown): number | undefined {
35+const numeric =
36+typeof value === "number" ? value : typeof value === "string" ? Number(value) : Number.NaN;
37+if (!Number.isFinite(numeric) || numeric <= 0) {
38+return undefined;
39+}
40+return Math.min(Math.floor(numeric), MAX_DISCORD_GATEWAY_READY_TIMEOUT_MS);
41+}
42+43+export function resolveDiscordGatewayReadyTimeoutMs(params?: {
44+configuredTimeoutMs?: number;
45+env?: NodeJS.ProcessEnv;
46+}): number {
47+return (
48+normalizeGatewayReadyTimeoutMs(params?.configuredTimeoutMs) ??
49+normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ??
50+DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS
51+);
52+}
53+54+export function resolveDiscordGatewayRuntimeReadyTimeoutMs(params?: {
55+configuredTimeoutMs?: number;
56+env?: NodeJS.ProcessEnv;
57+}): number {
58+return (
59+normalizeGatewayReadyTimeoutMs(params?.configuredTimeoutMs) ??
60+normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ??
61+DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS
62+);
63+}
64+3165async function restartGatewayAfterReadyTimeout(params: {
3266gateway?: Pick<MutableDiscordGateway, "connect" | "disconnect" | "ws">;
3367abortSignal?: AbortSignal;
@@ -158,6 +192,7 @@ function createGatewayStatusObserver(params: {
158192runtime: RuntimeEnv;
159193pushStatus: (patch: Parameters<DiscordMonitorStatusSink>[0]) => void;
160194isLifecycleStopping: () => boolean;
195+runtimeReadyTimeoutMs: number;
161196}) {
162197let forceStopHandler: ((err: unknown) => void) | undefined;
163198let queuedForceStopError: unknown;
@@ -214,7 +249,7 @@ function createGatewayStatusObserver(params: {
214249}
215250const at = Date.now();
216251const error = new Error(
217-`discord gateway opened but did not reach READY within ${DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS}ms`,
252+`discord gateway opened but did not reach READY within ${params.runtimeReadyTimeoutMs}ms`,
218253);
219254params.pushStatus({
220255connected: false,
@@ -227,7 +262,7 @@ function createGatewayStatusObserver(params: {
227262});
228263params.runtime.error?.(danger(error.message));
229264triggerForceStop(error);
230-}, DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS);
265+}, params.runtimeReadyTimeoutMs);
231266readyTimeoutId.unref?.();
232267}
233268};
@@ -292,9 +327,10 @@ async function waitForGatewayReady(params: {
292327pushStatus?: (patch: Parameters<DiscordMonitorStatusSink>[0]) => void;
293328runtime: RuntimeEnv;
294329beforeRestart?: () => Promise<void> | void;
330+readyTimeoutMs: number;
295331}): Promise<void> {
296332const waitUntilReady = async (): Promise<GatewayReadyWaitResult> => {
297-const deadlineAt = Date.now() + DISCORD_GATEWAY_READY_TIMEOUT_MS;
333+const deadlineAt = Date.now() + params.readyTimeoutMs;
298334while (!params.abortSignal?.aborted) {
299335if ((await params.beforePoll?.()) === "stop") {
300336return "stopped";
@@ -324,16 +360,12 @@ async function waitForGatewayReady(params: {
324360return;
325361}
326362if (!params.gateway) {
327-throw new Error(
328-`discord gateway did not reach READY within ${DISCORD_GATEWAY_READY_TIMEOUT_MS}ms`,
329-);
363+throw new Error(`discord gateway did not reach READY within ${params.readyTimeoutMs}ms`);
330364}
331365332366const restartAt = Date.now();
333367params.runtime.error?.(
334-danger(
335-`discord: gateway was not ready after ${DISCORD_GATEWAY_READY_TIMEOUT_MS}ms; restarting gateway`,
336-),
368+danger(`discord: gateway was not ready after ${params.readyTimeoutMs}ms; restarting gateway`),
337369);
338370params.pushStatus?.({
339371connected: false,
@@ -356,7 +388,7 @@ async function waitForGatewayReady(params: {
356388357389if ((await waitUntilReady()) === "timeout") {
358390throw new Error(
359-`discord gateway did not reach READY within ${DISCORD_GATEWAY_READY_TIMEOUT_MS}ms after restart`,
391+`discord gateway did not reach READY within ${params.readyTimeoutMs}ms after restart`,
360392);
361393}
362394}
@@ -372,6 +404,8 @@ export async function runDiscordGatewayLifecycle(params: {
372404threadBindings: { stop: () => void };
373405gatewaySupervisor: DiscordGatewaySupervisor;
374406statusSink?: DiscordMonitorStatusSink;
407+gatewayReadyTimeoutMs?: number;
408+gatewayRuntimeReadyTimeoutMs?: number;
375409}) {
376410const gateway = params.gateway;
377411if (gateway) {
@@ -387,12 +421,21 @@ export async function runDiscordGatewayLifecycle(params: {
387421const pushStatus = (patch: Parameters<DiscordMonitorStatusSink>[0]) => {
388422params.statusSink?.(patch);
389423};
424+const gatewayReadyTimeoutMs = resolveDiscordGatewayReadyTimeoutMs({
425+configuredTimeoutMs: params.gatewayReadyTimeoutMs,
426+env: process.env,
427+});
428+const gatewayRuntimeReadyTimeoutMs = resolveDiscordGatewayRuntimeReadyTimeoutMs({
429+configuredTimeoutMs: params.gatewayRuntimeReadyTimeoutMs,
430+env: process.env,
431+});
390432const statusObserver = createGatewayStatusObserver({
391433 gateway,
392434abortSignal: params.abortSignal,
393435runtime: params.runtime,
394436 pushStatus,
395437isLifecycleStopping: () => lifecycleStopping,
438+runtimeReadyTimeoutMs: gatewayRuntimeReadyTimeoutMs,
396439});
397440gatewayEmitter?.on("debug", statusObserver.onGatewayDebug);
398441let lastTransportActivityStatusAt: number | undefined;
@@ -460,6 +503,7 @@ export async function runDiscordGatewayLifecycle(params: {
460503 pushStatus,
461504runtime: params.runtime,
462505beforeRestart: statusObserver.clearReadyWatch,
506+readyTimeoutMs: gatewayReadyTimeoutMs,
463507});
464508465509if (drainPendingGatewayErrors() === "stop") {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。