fix(server-s3): transcript snapshot copies asynchronously (F42 follow-up)

copyIfNewer read/wrote a member file of up to 256 MiB with readSync/writeSync,
blocking the event loop for every user. It now copies with fs.promises 1 MiB
at a time from the runAs.openSafeAsync handle (owner/type check kept), keeps
the 256 MiB member cap and zero-run holes, writes a temp file and renames it
into place, and joins a copy already in flight for the same destination.
A failed copy is logged and never rejects; snapshotTranscript is async and
all three import callers await it.
This commit is contained in:
2026-10-09 15:17:55 +07:00
parent 84e2a9f0ac
commit 3ab750c765
6 changed files with 130 additions and 33 deletions
@@ -235,7 +235,7 @@ describe("snapshotTranscript (durable nested-layout fallback)", () => {
]);
});
it("preserves the nested layout into the snapshot so the read route resolves it", () => {
it("preserves the nested layout into the snapshot so the read route resolves it", async () => {
// Build an independent source session, snapshot it, then resolve from the
// snapshot dir exactly as the route's third fallback does.
const srcMain = path.join(ENC_DIR, `${SESSION_SNAP}.jsonl`);
@@ -250,15 +250,15 @@ describe("snapshotTranscript (durable nested-layout fallback)", () => {
writeFile(srcMain, jsonl([{ type: "summary", summary: "snap" }]));
writeFile(srcNested, transcriptJsonl(PROMPT_TEXT, LONG_RESULT));
snapshotTranscript(srcMain, SESSION_SNAP);
await snapshotTranscript(srcMain, SESSION_SNAP);
const snapHit = getSnapshotSubagentTranscriptPath(SESSION_SNAP, WF_ID, RUN1);
assert.ok(snapHit, "snapshot resolver should find the preserved nested transcript");
assert.equal(fs.readFileSync(snapHit, "utf8"), fs.readFileSync(srcNested, "utf8"));
});
it("does not throw for a session with no transcripts", () => {
assert.doesNotThrow(() => snapshotTranscript(path.join(ENC_DIR, "nope.jsonl"), "nope"));
it("does not throw for a session with no transcripts", async () => {
await assert.doesNotReject(snapshotTranscript(path.join(ENC_DIR, "nope.jsonl"), "nope"));
});
});