fix(agent): released ollama-cloud semaphore slot when waiter aborts
Semaphore.acquire now accepts an AbortSignal so a queued waiter that is cancelled (parent task abort, wall-clock budget elapsing) removes itself from the wait queue instead of being resolved by the next release. The provider semaphore in runSubprocess passes the run's abortSignal through, preventing aborted ollama-cloud subagents from permanently draining the provider concurrency budget. Fixes #3464
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
import { AuthStorage } from "@oh-my-pi/pi-coding-agent/session/auth-storage";
|
||||
import { SessionManager } from "@oh-my-pi/pi-coding-agent/session/session-manager";
|
||||
import { runSubprocess } from "@oh-my-pi/pi-coding-agent/task/executor";
|
||||
import { Semaphore } from "@oh-my-pi/pi-coding-agent/task/parallel";
|
||||
import type { AgentDefinition } from "@oh-my-pi/pi-coding-agent/task/types";
|
||||
import { EventBus } from "@oh-my-pi/pi-coding-agent/utils/event-bus";
|
||||
import { TempDir } from "@oh-my-pi/pi-utils";
|
||||
@@ -217,4 +218,28 @@ describe("issue #3464: ollama-cloud task backoff", () => {
|
||||
gates.get("CloudTwo")?.resolve();
|
||||
await second;
|
||||
});
|
||||
|
||||
it("frees a queued slot when its acquire waiter is aborted", async () => {
|
||||
const semaphore = new Semaphore(1);
|
||||
await semaphore.acquire();
|
||||
const controller = new AbortController();
|
||||
const aborted = semaphore.acquire(controller.signal);
|
||||
controller.abort();
|
||||
await aborted.then(
|
||||
() => {
|
||||
throw new Error("Aborted semaphore.acquire should reject");
|
||||
},
|
||||
() => {},
|
||||
);
|
||||
|
||||
const nextStarted = deferred();
|
||||
const next = (async () => {
|
||||
await semaphore.acquire();
|
||||
nextStarted.resolve();
|
||||
})();
|
||||
semaphore.release();
|
||||
await nextStarted.promise;
|
||||
semaphore.release();
|
||||
await next;
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user