mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 16:27:18 +02:00
Keep the dedicated workspace-copyback transaction active with bounded SELECT 1 probes while filesystem work runs. Preserve existing connection, owner-token, takeover and publication fences.
Verified head 7fb0ad45bf: full CI, E2E, Superagent, legacy statuses and Apex 5/5; no unresolved review findings. Real PostgreSQL idle-timeout reproduction and 71 affected cases pass. Strengthened disabled-timeout controls fail when their guard is removed.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
26 lines
790 B
TypeScript
26 lines
790 B
TypeScript
import { setTimeout } from "node:timers/promises";
|
|
import { sql } from "drizzle-orm";
|
|
import type { Db } from "@paperclipai/db";
|
|
|
|
export async function withWorkspaceLockKeepalive<T>(
|
|
lock: Pick<Db, "execute">,
|
|
idleTimeoutMs: number,
|
|
work: () => Promise<T>,
|
|
): Promise<T> {
|
|
if (!Number.isFinite(idleTimeoutMs) || idleTimeoutMs <= 0) return work();
|
|
const stop = new AbortController();
|
|
const interval = Math.max(1, Math.min(30_000, Math.floor(idleTimeoutMs / 3)));
|
|
const keeper = (async () => {
|
|
while (!stop.signal.aborted) {
|
|
await setTimeout(interval, undefined, { signal: stop.signal, ref: false });
|
|
await lock.execute(sql`select 1`);
|
|
}
|
|
})().catch(() => undefined);
|
|
try {
|
|
return await work();
|
|
} finally {
|
|
stop.abort();
|
|
await keeper;
|
|
}
|
|
}
|