mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 21:44:47 +00:00
fix(gateway): quiet startup retry closes
Co-authored-by: JARVIS-Glasses <284122573+JARVIS-Glasses@users.noreply.github.com> Co-authored-by: WhatsSkiLL <284126683+IWhatsskill@users.noreply.github.com>
This commit is contained in:
@@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
|
||||
- CLI/dashboard: probe Gateway readiness before handing out the dashboard URL, prompting to start or install the managed service when the Gateway is stopped and printing recovery commands instead of opening a dead browser tab.
|
||||
- CLI: hide decorative startup and status emoji on terminals that are unlikely to render them correctly, keeping semantic message and identity emoji intact.
|
||||
- CLI/gateway: recover the Linux user systemd bus environment when `openclaw dashboard` starts the Gateway from stripped desktop shells such as VNC terminals.
|
||||
- Gateway/WebSocket: log expected startup `1013 gateway starting` retry closes at debug instead of warn while preserving WARN for unexpected pre-connect failures. Fixes #76361. (#82457) Thanks @IWhatsskill.
|
||||
- CLI/context engines: bootstrap and finalize non-legacy context engines for CLI turns while preserving transcript snapshots and deferred maintenance ownership. (#81869) Thanks @sahilsatralkar.
|
||||
- Telegram: persist polling updates through restart replay so queued same-topic messages resume in order instead of losing context after a gateway restart. (#82256) Thanks @VACInc.
|
||||
- Gateway/Gmail: abort in-flight Gmail watcher startup and hot-reload restarts before shutdown so reloads cannot spawn `gog serve` after the Gateway is closing. Thanks @frankekn.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export const GATEWAY_STARTUP_UNAVAILABLE_REASON = "startup-sidecars";
|
||||
export const GATEWAY_STARTUP_PENDING_CLOSE_CAUSE = "startup-sidecars-pending";
|
||||
export const GATEWAY_STARTUP_CLOSE_CODE = 1013;
|
||||
export const GATEWAY_STARTUP_CLOSE_REASON = "gateway starting";
|
||||
export const GATEWAY_STARTUP_RETRY_AFTER_MS = 500;
|
||||
const GATEWAY_STARTUP_RETRY_MIN_MS = 100;
|
||||
const GATEWAY_STARTUP_RETRY_MAX_MS = 2_000;
|
||||
|
||||
@@ -3,7 +3,12 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import type { WebSocketServer } from "ws";
|
||||
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../protocol/client-info.js";
|
||||
import { PROTOCOL_VERSION } from "../protocol/index.js";
|
||||
import { GATEWAY_STARTUP_UNAVAILABLE_REASON } from "../protocol/startup-unavailable.js";
|
||||
import {
|
||||
GATEWAY_STARTUP_CLOSE_CODE,
|
||||
GATEWAY_STARTUP_CLOSE_REASON,
|
||||
GATEWAY_STARTUP_PENDING_CLOSE_CAUSE,
|
||||
GATEWAY_STARTUP_UNAVAILABLE_REASON,
|
||||
} from "../protocol/startup-unavailable.js";
|
||||
import { attachGatewayWsConnectionHandler } from "./ws-connection.js";
|
||||
|
||||
function createLogger() {
|
||||
@@ -51,6 +56,7 @@ describe("attachGatewayWsConnectionHandler startup readiness", () => {
|
||||
headers: { host: "127.0.0.1:19001" },
|
||||
socket: { localAddress: "127.0.0.1" },
|
||||
};
|
||||
const logWsControl = createLogger();
|
||||
|
||||
attachGatewayWsConnectionHandler({
|
||||
wss,
|
||||
@@ -64,7 +70,7 @@ describe("attachGatewayWsConnectionHandler startup readiness", () => {
|
||||
refreshHealthSnapshot: vi.fn(async () => ({}) as never),
|
||||
logGateway: createLogger() as never,
|
||||
logHealth: createLogger() as never,
|
||||
logWsControl: createLogger() as never,
|
||||
logWsControl: logWsControl as never,
|
||||
extraHandlers: {},
|
||||
broadcast: vi.fn(),
|
||||
buildRequestContext: () => createRequestContext() as never,
|
||||
@@ -134,7 +140,25 @@ describe("attachGatewayWsConnectionHandler startup readiness", () => {
|
||||
expect(response?.error?.retryAfterMs).toBe(500);
|
||||
expect(response?.error?.details).toEqual({ reason: GATEWAY_STARTUP_UNAVAILABLE_REASON });
|
||||
await vi.waitFor(() => {
|
||||
expect(socket.close).toHaveBeenCalledWith(1013, "gateway starting");
|
||||
expect(socket.close).toHaveBeenCalledWith(
|
||||
GATEWAY_STARTUP_CLOSE_CODE,
|
||||
GATEWAY_STARTUP_CLOSE_REASON,
|
||||
);
|
||||
});
|
||||
expect(logWsControl.debug).toHaveBeenCalledWith(
|
||||
expect.stringContaining("closed before connect"),
|
||||
expect.objectContaining({
|
||||
cause: GATEWAY_STARTUP_PENDING_CLOSE_CAUSE,
|
||||
handshake: "failed",
|
||||
}),
|
||||
);
|
||||
expect(logWsControl.debug).toHaveBeenCalledWith(
|
||||
expect.stringContaining(`code=${GATEWAY_STARTUP_CLOSE_CODE}`),
|
||||
expect.anything(),
|
||||
);
|
||||
expect(logWsControl.warn).not.toHaveBeenCalledWith(
|
||||
expect.stringContaining("closed before connect"),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,10 @@ import { resolveHostedPluginSurfaceUrl } from "../hosted-plugin-surface-url.js";
|
||||
import type { GatewayMethodRegistry } from "../methods/registry.js";
|
||||
import { isLoopbackAddress } from "../net.js";
|
||||
import type { PluginNodeCapabilitySurface } from "../plugin-node-capability.js";
|
||||
import {
|
||||
GATEWAY_STARTUP_CLOSE_CODE,
|
||||
GATEWAY_STARTUP_PENDING_CLOSE_CAUSE,
|
||||
} from "../protocol/startup-unavailable.js";
|
||||
import { MAX_PAYLOAD_BYTES, MAX_PREAUTH_PAYLOAD_BYTES } from "../server-constants.js";
|
||||
import { clearNodeWakeState } from "../server-methods/nodes-wake-state.js";
|
||||
import type { GatewayRequestContext, GatewayRequestHandlers } from "../server-methods/types.js";
|
||||
@@ -377,9 +381,12 @@ export function attachGatewayWsConnectionHandler(params: AttachGatewayWsConnecti
|
||||
...closeMeta,
|
||||
};
|
||||
if (!client) {
|
||||
const logFn = isNoisySwiftPmHelperClose(requestUserAgent, remoteAddr)
|
||||
? logWsControl.debug
|
||||
: logWsControl.warn;
|
||||
const isExpectedStartupRetryClose =
|
||||
closeCause === GATEWAY_STARTUP_PENDING_CLOSE_CAUSE && code === GATEWAY_STARTUP_CLOSE_CODE;
|
||||
const logFn =
|
||||
isNoisySwiftPmHelperClose(requestUserAgent, remoteAddr) || isExpectedStartupRetryClose
|
||||
? logWsControl.debug
|
||||
: logWsControl.warn;
|
||||
logFn(
|
||||
`closed before connect conn=${connId} peer=${endpoint ?? "n/a"} remote=${remoteAddr ?? "?"} fwd=${logForwardedFor || "n/a"} origin=${logOrigin || "n/a"} host=${logHost || "n/a"} ua=${logUserAgent || "n/a"} code=${code ?? "n/a"} reason=${logReason || "n/a"}`,
|
||||
closeContext,
|
||||
|
||||
@@ -99,6 +99,9 @@ import {
|
||||
} from "../../protocol/index.js";
|
||||
import {
|
||||
gatewayStartupUnavailableDetails,
|
||||
GATEWAY_STARTUP_CLOSE_CODE,
|
||||
GATEWAY_STARTUP_CLOSE_REASON,
|
||||
GATEWAY_STARTUP_PENDING_CLOSE_CAUSE,
|
||||
GATEWAY_STARTUP_RETRY_AFTER_MS,
|
||||
} from "../../protocol/startup-unavailable.js";
|
||||
import { parseGatewayRole } from "../../role-policy.js";
|
||||
@@ -514,7 +517,7 @@ export function attachGatewayWsMessageHandler(params: GatewayWsMessageHandlerPar
|
||||
};
|
||||
|
||||
if (isStartupPending?.()) {
|
||||
markHandshakeFailure("startup-sidecars-pending");
|
||||
markHandshakeFailure(GATEWAY_STARTUP_PENDING_CLOSE_CAUSE);
|
||||
await sendFrame({
|
||||
type: "res",
|
||||
id: frame.id,
|
||||
@@ -525,7 +528,7 @@ export function attachGatewayWsMessageHandler(params: GatewayWsMessageHandlerPar
|
||||
details: gatewayStartupUnavailableDetails(),
|
||||
}),
|
||||
}).catch(() => {});
|
||||
queueMicrotask(() => close(1013, "gateway starting"));
|
||||
queueMicrotask(() => close(GATEWAY_STARTUP_CLOSE_CODE, GATEWAY_STARTUP_CLOSE_REASON));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user