UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

123 lines (122 loc) • 5.76 kB
import { d as readDatabasePathIdentitySync } from "./sqlite-worker-identity-BRNRpRyc.mjs"; import { r as getChildLogger } from "./logger-BhL9CiBr.mjs"; import { i as runQueuedStoreWrite, n as isActiveStoreWriter } from "./store-writer-queue-x_P9TrZs.mjs"; import { n as agentDatabaseWriteAdmissionState } from "./openclaw-agent-write-admission-state-MeRNaC3M.mjs"; import { l as resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db.paths-BbmZlEP5.mjs"; import { t as runStoreWriterAcquisitions } from "./store-writer-acquisitions-Q--yqQda.mjs"; import { isMainThread, threadId } from "node:worker_threads"; import { performance } from "node:perf_hooks"; //#region src/state/openclaw-agent-write-admission.ts function observeWriteAdmission(operation, timing, run) { if (timing) return run(timing); const observed = {}; const enqueuedAt = performance.now(); const report = (outcome) => { if (observed.reentrant !== false || observed.startedAt === void 0 || observed.finishedAt === void 0 || observed.finishedAt - observed.startedAt < 1e3) return; const completedAt = performance.now(); try { getChildLogger({ subsystem: "session-sqlite" }).warn({ operation, outcome, pid: process.pid, threadId, isMainThread, reentrant: false, elapsedMs: Math.round(completedAt - enqueuedAt), queueWaitMs: Math.round(observed.startedAt - enqueuedAt), writerExecutionMs: Math.round(observed.finishedAt - observed.startedAt), completionDelayMs: Math.round(completedAt - observed.finishedAt) }, "slow agent database reservation"); } catch {} }; return run(observed).then((value) => { report("ok"); return value; }, (error) => { report("error"); throw error; }); } function runOpenClawAgentWriteAdmission(options, run, reentrant = false, timing, signal) { const pathname = resolveOpenClawAgentSqlitePath(options); const identity = readDatabasePathIdentitySync(pathname); const storePath = identity.canonicalPath; const assertCurrent = () => { const current = readDatabasePathIdentitySync(pathname); if (current.canonicalPath !== storePath || identity.key.startsWith("file:") && (current.key !== identity.key || current.birthtime !== identity.birthtime)) throw new Error("Agent database target changed before write admission"); }; return observeWriteAdmission("direct", timing, (observed) => runQueuedStoreWrite({ queues: agentDatabaseWriteAdmissionState.queues, storePath, label: "agent database write admission", reentrant: reentrant && !agentDatabaseWriteAdmissionState.workers.has(storePath), fn: async () => { assertCurrent(); return await run(identity, assertCurrent); }, timing: observed, signal })); } /** Reserve a native write permit without admitting inherited foreground callbacks. */ function runOpenClawAgentWorkerWrite(options, run, timing, signal) { return observeWriteAdmission("worker", timing, (observed) => { if ("target" in options) { const { handle, incarnation } = options.target; return runQueuedStoreWrite({ queues: agentDatabaseWriteAdmissionState.queues, storePath: `ephemeral:${handle}:${incarnation}`, label: "incognito agent database write admission", reentrant: false, fn: async () => { options.assertCurrent(); return run(); }, timing: observed, signal }); } return runOpenClawAgentWriteAdmission(options, async ({ canonicalPath: storePath }) => { const owner = {}; agentDatabaseWriteAdmissionState.workers.set(storePath, owner); try { return await run(); } finally { if (agentDatabaseWriteAdmissionState.workers.get(storePath) === owner) agentDatabaseWriteAdmissionState.workers.delete(storePath); } }, true, observed, signal); }); } /** Compose the existing foreground queues without inverting inherited acquisition order. */ async function runOpenClawAgentWriteAdmissions(options, run, reentrant = false, signal) { signal?.throwIfAborted(); let selected = new Map(options.map((option) => [resolveOpenClawAgentSqlitePath(option), option])); const inherited = [...agentDatabaseWriteAdmissionState.queues.keys()].filter((pathname) => isActiveStoreWriter(agentDatabaseWriteAdmissionState.queues, pathname)); if (selected.size > 1) { const physicalKey = (pathname) => { const identity = readDatabasePathIdentitySync(pathname); return `${identity.key}:${identity.birthtime ?? ""}`; }; const representatives = new Map(inherited.map((pathname) => [physicalKey(pathname), pathname])); const physical = /* @__PURE__ */ new Map(); for (const [pathname, option] of selected) { const identity = physicalKey(pathname); const representative = representatives.get(identity) ?? pathname; representatives.set(identity, representative); physical.set(representative, { ...option, path: representative }); } selected = physical; } const paths = [...selected.keys()].toSorted(); if (paths.some((pathname) => inherited.includes(pathname) && (!reentrant || paths.length !== 1 || agentDatabaseWriteAdmissionState.workers.has(pathname)))) throw new Error("Session read batch cannot reenter an active SQLite writer admission"); if (paths.some((pathname) => inherited.some((held) => held > pathname))) throw new Error("Session read batch would invert inherited SQLite writer admission order"); return await runStoreWriterAcquisitions((index, next) => { const pathname = paths[index]; return pathname === void 0 ? Promise.resolve().then(run) : observeWriteAdmission("ordered-read", void 0, (timing) => runOpenClawAgentWriteAdmission(selected.get(pathname), next, true, timing, signal)); }); } //#endregion export { runOpenClawAgentWriteAdmission as n, runOpenClawAgentWriteAdmissions as r, runOpenClawAgentWorkerWrite as t };