mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(coding-agent): shorten file lock retry delays
This commit is contained in:
parent
2c79ce4532
commit
4d68d93551
2 changed files with 29 additions and 6 deletions
|
|
@ -117,15 +117,18 @@ export class FileAuthStorageBackend implements AuthStorageBackend {
|
|||
signal: AbortSignal | undefined,
|
||||
onCompromised: (error: Error) => void,
|
||||
): Promise<() => Promise<void>> {
|
||||
const maxRetries = 10;
|
||||
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
||||
const staleMs = 30_000;
|
||||
const maxDelayMs = 2_000;
|
||||
const deadline = Date.now() + staleMs;
|
||||
let retry = 0;
|
||||
while (true) {
|
||||
signal?.throwIfAborted();
|
||||
let release: (() => Promise<void>) | undefined;
|
||||
try {
|
||||
release = await lockfile.lock(this.authPath, {
|
||||
realpath: false,
|
||||
retries: 0,
|
||||
stale: 30000,
|
||||
stale: staleMs,
|
||||
onCompromised,
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
@ -134,8 +137,11 @@ export class FileAuthStorageBackend implements AuthStorageBackend {
|
|||
typeof error === "object" && error !== null && "code" in error
|
||||
? String((error as { code?: unknown }).code)
|
||||
: undefined;
|
||||
if (code !== "ELOCKED" || attempt === maxRetries) throw error;
|
||||
const delayMs = Math.min(Math.round((Math.random() + 1) * 100 * 2 ** attempt), 10000);
|
||||
const remainingMs = deadline - Date.now();
|
||||
if (code !== "ELOCKED" || remainingMs <= 0) throw error;
|
||||
const baseDelayMs = Math.min(10 * 2 ** retry, maxDelayMs / 2);
|
||||
retry++;
|
||||
const delayMs = Math.min(Math.round(baseDelayMs * (1 + Math.random())), remainingMs);
|
||||
if (signal) await sleep(delayMs, undefined, { signal });
|
||||
else await sleep(delayMs);
|
||||
continue;
|
||||
|
|
@ -146,7 +152,6 @@ export class FileAuthStorageBackend implements AuthStorageBackend {
|
|||
}
|
||||
return release;
|
||||
}
|
||||
throw new Error("Failed to acquire auth storage lock");
|
||||
}
|
||||
|
||||
async withLockAsync<T>(
|
||||
|
|
|
|||
|
|
@ -226,6 +226,24 @@ describe("AuthStorage", () => {
|
|||
});
|
||||
});
|
||||
|
||||
test("retries a briefly contended file lock", async () => {
|
||||
writeAuthJson({ anthropic: { type: "api_key", key: "stored" } });
|
||||
const backend = new FileAuthStorageBackend(authJsonPath);
|
||||
const release = vi.fn(async () => {});
|
||||
const lockSpy = vi
|
||||
.spyOn(lockfile, "lock")
|
||||
.mockRejectedValueOnce(Object.assign(new Error("locked"), { code: "ELOCKED" }))
|
||||
.mockResolvedValueOnce(release);
|
||||
vi.spyOn(Math, "random").mockReturnValue(0);
|
||||
const update = vi.fn(async () => ({ result: undefined }));
|
||||
|
||||
await backend.withLockAsync(update);
|
||||
|
||||
expect(lockSpy).toHaveBeenCalledTimes(2);
|
||||
expect(update).toHaveBeenCalledTimes(1);
|
||||
expect(release).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("surfaces a compromised file storage lock", async () => {
|
||||
writeAuthJson({ anthropic: { type: "api_key", key: "stored" } });
|
||||
const backend = new FileAuthStorageBackend(authJsonPath);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue