mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 09:10:45 +00:00
fix(codex): scope stale shared-client cleanup
This commit is contained in:
committed by
Peter Steinberger
parent
0bc5ccc706
commit
15f285c0cb
@@ -144,4 +144,47 @@ describe("shared Codex app-server client", () => {
|
||||
expect(startSpy).toHaveBeenCalledTimes(2);
|
||||
expect(first.process.kill).toHaveBeenCalledWith("SIGTERM");
|
||||
});
|
||||
|
||||
it("does not let a superseded shared-client failure tear down the newer client", async () => {
|
||||
const first = createClientHarness();
|
||||
const second = createClientHarness();
|
||||
vi.spyOn(CodexAppServerClient, "start")
|
||||
.mockReturnValueOnce(first.client)
|
||||
.mockReturnValueOnce(second.client);
|
||||
|
||||
const firstList = listCodexAppServerModels({
|
||||
timeoutMs: 1000,
|
||||
startOptions: {
|
||||
transport: "websocket",
|
||||
command: "codex",
|
||||
args: [],
|
||||
url: "ws://127.0.0.1:39175",
|
||||
authToken: "tok-first",
|
||||
headers: {},
|
||||
},
|
||||
});
|
||||
const firstFailure = firstList.catch((error: unknown) => error);
|
||||
await vi.waitFor(() => expect(first.writes.length).toBeGreaterThanOrEqual(1));
|
||||
|
||||
const secondList = listCodexAppServerModels({
|
||||
timeoutMs: 1000,
|
||||
startOptions: {
|
||||
transport: "websocket",
|
||||
command: "codex",
|
||||
args: [],
|
||||
url: "ws://127.0.0.1:39175",
|
||||
authToken: "tok-second",
|
||||
headers: {},
|
||||
},
|
||||
});
|
||||
await vi.waitFor(() => expect(second.writes.length).toBeGreaterThanOrEqual(1));
|
||||
|
||||
await expect(firstFailure).resolves.toBeInstanceOf(Error);
|
||||
|
||||
await sendInitializeResult(second, "openclaw/0.118.0 (macOS; test)");
|
||||
await sendEmptyModelList(second);
|
||||
await expect(secondList).resolves.toEqual({ models: [] });
|
||||
|
||||
expect(second.process.kill).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,28 +40,32 @@ export async function getSharedCodexAppServerClient(options?: {
|
||||
clearSharedCodexAppServerClient();
|
||||
}
|
||||
state.key = key;
|
||||
state.promise ??= (async () => {
|
||||
const client = CodexAppServerClient.start(startOptions);
|
||||
state.client = client;
|
||||
client.addCloseHandler(clearSharedClientIfCurrent);
|
||||
try {
|
||||
await client.initialize();
|
||||
const sharedPromise =
|
||||
state.promise ??
|
||||
(state.promise = (async () => {
|
||||
const client = CodexAppServerClient.start(startOptions);
|
||||
state.client = client;
|
||||
client.addCloseHandler(clearSharedClientIfCurrent);
|
||||
try {
|
||||
await client.initialize();
|
||||
return client;
|
||||
} catch (error) {
|
||||
// Startup failures happen before callers own the shared client, so close
|
||||
// the child here instead of leaving a rejected daemon attached to stdio.
|
||||
client.close();
|
||||
throw error;
|
||||
}
|
||||
})();
|
||||
client.close();
|
||||
throw error;
|
||||
}
|
||||
})());
|
||||
try {
|
||||
return await withTimeout(
|
||||
state.promise,
|
||||
sharedPromise,
|
||||
options?.timeoutMs ?? 0,
|
||||
"codex app-server initialize timed out",
|
||||
);
|
||||
} catch (error) {
|
||||
clearSharedCodexAppServerClient();
|
||||
if (state.promise === sharedPromise && state.key === key) {
|
||||
clearSharedCodexAppServerClient();
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user