Skip to content

Commit 1163797

Browse files
committed
fix: harden connection manager request cleanup
1 parent ab75451 commit 1163797

3 files changed

Lines changed: 36 additions & 4 deletions

File tree

deno.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"version": "0.0.0-development",
55
"license": "MIT",
66
"tasks": {
7-
"build": "deno run -A dnt.ts",
87
"check": "deno check src/index.ts",
98
"dev": "deno run --allow-all src/index.ts",
109
"lint": "deno lint",

src/services/connection-manager.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,32 @@ describe("connection manager", () => {
10091009
);
10101010
});
10111011

1012+
it("does not leak active request controllers when callTool throws synchronously", async () => {
1013+
const manager = new GraphitiConnectionManager({
1014+
endpoint: "http://test",
1015+
connectionFactory: () => ({
1016+
connect: () => Promise.resolve(),
1017+
close: () => Promise.resolve(),
1018+
callTool: () => {
1019+
throw new Error("sync boom");
1020+
},
1021+
}),
1022+
});
1023+
const internals = manager as unknown as {
1024+
activeRequestControllers: Set<AbortController>;
1025+
};
1026+
1027+
manager.start();
1028+
assertEquals(await manager.ready(10), true);
1029+
1030+
await assertRejects(
1031+
() => manager.callTool("search", {}),
1032+
Error,
1033+
"sync boom",
1034+
);
1035+
assertEquals(internals.activeRequestControllers.size, 0);
1036+
});
1037+
10121038
it("rejects invalid non-empty endpoints up front", () => {
10131039
const error = assertThrows(
10141040
() =>

src/services/connection-manager.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -491,11 +491,18 @@ export class GraphitiConnectionManager implements GraphitiToolCaller {
491491
try {
492492
const controller = new AbortController();
493493
this.activeRequestControllers.add(controller);
494-
return await this.runWithRequestDeadline(
495-
this.connection.callTool(
494+
let task: Promise<unknown>;
495+
try {
496+
task = this.connection.callTool(
496497
{ name, arguments: args },
497498
{ signal: controller.signal },
498-
),
499+
);
500+
} catch (err) {
501+
this.activeRequestControllers.delete(controller);
502+
throw err;
503+
}
504+
return await this.runWithRequestDeadline(
505+
task,
499506
deadlineMs,
500507
controller,
501508
);

0 commit comments

Comments
 (0)