mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:30:44 +00:00
fix: bound message CLI shutdown hooks
This commit is contained in:
@@ -144,6 +144,41 @@ describe("runMessageAction", () => {
|
||||
expect(exitMock).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("skips gateway_stop hooks for read-only message reads", async () => {
|
||||
hasHooksMock.mockReturnValueOnce(true);
|
||||
const runMessageAction = createRunMessageAction();
|
||||
|
||||
await expect(
|
||||
runMessageAction("read", {
|
||||
channel: "discord",
|
||||
target: "channel:123",
|
||||
limit: 1,
|
||||
}),
|
||||
).rejects.toThrow("exit");
|
||||
|
||||
expect(runGlobalGatewayStopSafelyMock).not.toHaveBeenCalled();
|
||||
expect(runGatewayStopMock).not.toHaveBeenCalled();
|
||||
expect(exitMock).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
it("bounds gateway_stop hooks so message actions still exit", async () => {
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
hasHooksMock.mockReturnValueOnce(true);
|
||||
runGatewayStopMock.mockImplementationOnce(() => new Promise(() => undefined));
|
||||
const runMessageAction = createRunMessageAction();
|
||||
|
||||
const pending = expect(runMessageAction("send", baseSendOptions)).rejects.toThrow("exit");
|
||||
await vi.advanceTimersByTimeAsync(2500);
|
||||
await pending;
|
||||
|
||||
expect(errorMock).toHaveBeenCalledWith("gateway_stop hook exceeded 2500ms; continuing");
|
||||
expect(exitMock).toHaveBeenCalledWith(0);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("calls exit(1) when message delivery fails", async () => {
|
||||
messageCommandMock.mockRejectedValueOnce(new Error("send failed"));
|
||||
await runSendAction();
|
||||
|
||||
@@ -16,6 +16,9 @@ export type MessageCliHelpers = {
|
||||
runMessageAction: (action: string, opts: Record<string, unknown>) => Promise<void>;
|
||||
};
|
||||
|
||||
const GATEWAY_STOP_TIMEOUT_MS = 2500;
|
||||
const ACTIONS_WITHOUT_STOP_HOOKS = new Set(["read"]);
|
||||
|
||||
function normalizeMessageOptions(opts: Record<string, unknown>): Record<string, unknown> {
|
||||
const { account, ...rest } = opts;
|
||||
return {
|
||||
@@ -25,11 +28,25 @@ function normalizeMessageOptions(opts: Record<string, unknown>): Record<string,
|
||||
}
|
||||
|
||||
async function runPluginStopHooks(): Promise<void> {
|
||||
await runGlobalGatewayStopSafely({
|
||||
let timeout: NodeJS.Timeout | null = null;
|
||||
const hookRun = runGlobalGatewayStopSafely({
|
||||
event: { reason: "cli message action complete" },
|
||||
ctx: {},
|
||||
onError: (err) => defaultRuntime.error(danger(`gateway_stop hook failed: ${String(err)}`)),
|
||||
});
|
||||
const bounded = new Promise<"timeout">((resolve) => {
|
||||
timeout = setTimeout(() => resolve("timeout"), GATEWAY_STOP_TIMEOUT_MS);
|
||||
timeout.unref?.();
|
||||
});
|
||||
const result = await Promise.race([hookRun.then(() => "done" as const), bounded]);
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
if (result === "timeout") {
|
||||
defaultRuntime.error(
|
||||
danger(`gateway_stop hook exceeded ${GATEWAY_STOP_TIMEOUT_MS}ms; continuing`),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveMessagePluginLoadOptions(
|
||||
@@ -85,7 +102,9 @@ export function createMessageCliHelpers(
|
||||
defaultRuntime.error(danger(String(err)));
|
||||
},
|
||||
);
|
||||
await runPluginStopHooks();
|
||||
if (!ACTIONS_WITHOUT_STOP_HOOKS.has(action)) {
|
||||
await runPluginStopHooks();
|
||||
}
|
||||
defaultRuntime.exit(failed ? 1 : 0);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user