mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
fix(gateway): order bootstrap cache clear after embedded run wait
Landed from #38873 by @MumuTW. Co-authored-by: MumuTW <clothl47364@gmail.com>
This commit is contained in:
@@ -272,6 +272,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/OpenAI WS reconnect retry accounting: avoid double retry scheduling when reconnect failures emit both `error` and `close`, so retry budgets track actual reconnect attempts instead of exhausting early. (#39133) Thanks @scoootscooob.
|
||||
- Daemon/Windows schtasks runtime detection: use locale-invariant `Last Run Result` running codes (`0x41301`/`267009`) as the primary running signal so `openclaw node status` no longer misreports active tasks as stopped on non-English Windows locales. (#39076) Thanks @ademczuk.
|
||||
- Usage/token count formatting: round near-million token counts to millions (`1.0m`) instead of `1000k`, with explicit boundary coverage for `999_499` and `999_500`. (#39129) Thanks @CurryMessi.
|
||||
- Gateway/session bootstrap cache invalidation ordering: clear bootstrap snapshots only after active embedded-run shutdown wait completes, preventing dying runs from repopulating stale cache between `/new`/`sessions.reset` turns. (#38873) Thanks @MumuTW.
|
||||
|
||||
## 2026.3.2
|
||||
|
||||
|
||||
@@ -207,14 +207,15 @@ async function ensureSessionRuntimeCleanup(params: {
|
||||
queueKeys.add(params.sessionId);
|
||||
}
|
||||
clearSessionQueues([...queueKeys]);
|
||||
clearBootstrapSnapshot(params.target.canonicalKey);
|
||||
stopSubagentsForRequester({ cfg: params.cfg, requesterSessionKey: params.target.canonicalKey });
|
||||
if (!params.sessionId) {
|
||||
clearBootstrapSnapshot(params.target.canonicalKey);
|
||||
await closeTrackedBrowserTabs();
|
||||
return undefined;
|
||||
}
|
||||
abortEmbeddedPiRun(params.sessionId);
|
||||
const ended = await waitForEmbeddedPiRunEnd(params.sessionId, 15_000);
|
||||
clearBootstrapSnapshot(params.target.canonicalKey);
|
||||
if (ended) {
|
||||
await closeTrackedBrowserTabs();
|
||||
return undefined;
|
||||
|
||||
@@ -23,6 +23,10 @@ const sessionCleanupMocks = vi.hoisted(() => ({
|
||||
stopSubagentsForRequester: vi.fn(() => ({ stopped: 0 })),
|
||||
}));
|
||||
|
||||
const bootstrapCacheMocks = vi.hoisted(() => ({
|
||||
clearBootstrapSnapshot: vi.fn(),
|
||||
}));
|
||||
|
||||
const sessionHookMocks = vi.hoisted(() => ({
|
||||
triggerInternalHook: vi.fn(async () => {}),
|
||||
}));
|
||||
@@ -68,6 +72,14 @@ vi.mock("../auto-reply/reply/abort.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../agents/bootstrap-cache.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../agents/bootstrap-cache.js")>();
|
||||
return {
|
||||
...actual,
|
||||
clearBootstrapSnapshot: bootstrapCacheMocks.clearBootstrapSnapshot,
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("../hooks/internal-hooks.js", async () => {
|
||||
const actual = await vi.importActual<typeof import("../hooks/internal-hooks.js")>(
|
||||
"../hooks/internal-hooks.js",
|
||||
@@ -204,6 +216,7 @@ describe("gateway server sessions", () => {
|
||||
beforeEach(() => {
|
||||
sessionCleanupMocks.clearSessionQueues.mockClear();
|
||||
sessionCleanupMocks.stopSubagentsForRequester.mockClear();
|
||||
bootstrapCacheMocks.clearBootstrapSnapshot.mockReset();
|
||||
sessionHookMocks.triggerInternalHook.mockClear();
|
||||
subagentLifecycleHookMocks.runSubagentEnded.mockClear();
|
||||
subagentLifecycleHookState.hasSubagentEndedHook = true;
|
||||
@@ -926,6 +939,10 @@ describe("gateway server sessions", () => {
|
||||
|
||||
test("sessions.reset aborts active runs and clears queues", async () => {
|
||||
await seedActiveMainSession();
|
||||
const waitCallCountAtSnapshotClear: number[] = [];
|
||||
bootstrapCacheMocks.clearBootstrapSnapshot.mockImplementation(() => {
|
||||
waitCallCountAtSnapshotClear.push(embeddedRunMock.waitCalls.length);
|
||||
});
|
||||
|
||||
embeddedRunMock.activeIds.add("sess-main");
|
||||
embeddedRunMock.waitResults.set("sess-main", true);
|
||||
@@ -947,6 +964,7 @@ describe("gateway server sessions", () => {
|
||||
["main", "agent:main:main", "sess-main"],
|
||||
"sess-main",
|
||||
);
|
||||
expect(waitCallCountAtSnapshotClear).toEqual([1]);
|
||||
expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).toHaveBeenCalledTimes(1);
|
||||
expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).toHaveBeenCalledWith({
|
||||
sessionKeys: expect.arrayContaining(["main", "agent:main:main", "sess-main"]),
|
||||
@@ -1163,6 +1181,10 @@ describe("gateway server sessions", () => {
|
||||
|
||||
test("sessions.reset returns unavailable when active run does not stop", async () => {
|
||||
const { dir, storePath } = await seedActiveMainSession();
|
||||
const waitCallCountAtSnapshotClear: number[] = [];
|
||||
bootstrapCacheMocks.clearBootstrapSnapshot.mockImplementation(() => {
|
||||
waitCallCountAtSnapshotClear.push(embeddedRunMock.waitCalls.length);
|
||||
});
|
||||
|
||||
embeddedRunMock.activeIds.add("sess-main");
|
||||
embeddedRunMock.waitResults.set("sess-main", false);
|
||||
@@ -1180,6 +1202,7 @@ describe("gateway server sessions", () => {
|
||||
["main", "agent:main:main", "sess-main"],
|
||||
"sess-main",
|
||||
);
|
||||
expect(waitCallCountAtSnapshotClear).toEqual([1]);
|
||||
expect(browserSessionTabMocks.closeTrackedBrowserTabsForSessions).not.toHaveBeenCalled();
|
||||
|
||||
const store = JSON.parse(await fs.readFile(storePath, "utf-8")) as Record<
|
||||
|
||||
Reference in New Issue
Block a user