fix: continue subagent kill after session store write failures

This commit is contained in:
Tak Hoffman
2026-03-24 12:41:35 -05:00
parent 488ad4ac70
commit 7ab46301a9
2 changed files with 75 additions and 10 deletions

View File

@@ -1,8 +1,9 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import * as sessions from "../config/sessions.js";
import type { CallGatewayOptions } from "../gateway/call.js";
import {
__testing,
@@ -159,4 +160,60 @@ describe("killSubagentRunAdmin", () => {
expect(result).toEqual({ found: false, killed: false });
});
it("still terminates the run when session store persistence fails during kill", async () => {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-subagent-admin-kill-store-"));
const storePath = path.join(tmpDir, "sessions.json");
const childSessionKey = "agent:main:subagent:worker-store-fail";
fs.writeFileSync(
storePath,
JSON.stringify(
{
[childSessionKey]: {
sessionId: "sess-worker-store-fail",
updatedAt: Date.now(),
},
},
null,
2,
),
"utf-8",
);
addSubagentRunForTests({
runId: "run-worker-store-fail",
childSessionKey,
controllerSessionKey: "agent:main:other-controller",
requesterSessionKey: "agent:main:other-requester",
requesterDisplayKey: "other-requester",
task: "do the work",
cleanup: "keep",
createdAt: Date.now() - 5_000,
startedAt: Date.now() - 4_000,
});
const updateSessionStoreSpy = vi
.spyOn(sessions, "updateSessionStore")
.mockRejectedValueOnce(new Error("session store unavailable"));
try {
const result = await killSubagentRunAdmin({
cfg: {
session: { store: storePath },
} as OpenClawConfig,
sessionKey: childSessionKey,
});
expect(result).toMatchObject({
found: true,
killed: true,
runId: "run-worker-store-fail",
sessionKey: childSessionKey,
});
expect(getSubagentRunByChildSessionKey(childSessionKey)?.endedAt).toBeTypeOf("number");
} finally {
updateSessionStoreSpy.mockRestore();
}
});
});

View File

@@ -371,15 +371,23 @@ async function killSubagentRun(params: {
);
}
if (resolved.entry) {
await updateSessionStore(resolved.storePath, (store) => {
const current = store[childSessionKey];
if (!current) {
return;
}
current.abortedLastRun = true;
current.updatedAt = Date.now();
store[childSessionKey] = current;
});
try {
await updateSessionStore(resolved.storePath, (store) => {
const current = store[childSessionKey];
if (!current) {
return;
}
current.abortedLastRun = true;
current.updatedAt = Date.now();
store[childSessionKey] = current;
});
} catch (error) {
logVerbose(
`subagents control kill: failed to persist abortedLastRun for ${childSessionKey}: ${
error instanceof Error ? error.message : String(error)
}`,
);
}
}
const marked = markSubagentRunTerminated({
runId: params.entry.runId,