UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

143 lines (142 loc) • 7.16 kB
import { t as assertTransactionUsable } from "./sqlite-transaction-DBRLvCDM.mjs"; import { i as getSqliteWorkerStateContext } from "./sqlite-worker-state-context-G3Xbcj1W.mjs"; import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-DJZ7EKoI.mjs"; import { a as fingerprintCronRuntimeRows, i as fingerprintCronJobRows, n as deleteCronJobRowInDatabase, o as loadCronRows, s as loadedCronStoreFromRows } from "./row-codec-Fr_vfXdw.mjs"; import { t as loadCronRuntimeAuthorities } from "./runtime-authority-store-Cs7PX9bH.mjs"; import { r as isAgentDeletionBlocked } from "./agent-lifecycle-registry-CxGB4gfC.mjs"; import { t as readCronJobNamesInDatabase } from "./job-name.kernel-BWS3ffFU.mjs"; import { t as prepareCronRunReceiptWriteSchema } from "./run-receipt-write-admission-BaxZ24xP.mjs"; import { a as saveCronStoreInDatabase, c as CronJobsStoreChangedError, i as saveCronStoreChangesInDatabase, t as assertCronStoreChangesCurrent } from "./save.kernel-CqCUdo5e.mjs"; import { t as resolveCronJobConfigRevision } from "./config-revision-CA1eZYCq.mjs"; import { a as adjudicateActiveCronRunReceiptInDatabase, m as findActiveCronRunReceiptInDatabase, n as CronRunReceiptConflictError } from "./run-receipt-store-x-vqyPC9.mjs"; import { n as prepareCronRuntimeMutation, r as retainCronRuntimeMutationOutcome } from "./runtime-mutation.worker-BlscaPpT.mjs"; import { t as findCronRunRecoveryInDatabase } from "./run-history-recovery-CSeim9mn.mjs"; import { n as retireCronRunTriggerStateInDatabase } from "./run-receipt-trigger-state-CTS21mQl.mjs"; import { isDeepStrictEqual } from "node:util"; import { randomUUID } from "node:crypto"; //#region src/cron/store/guarded-mutation.worker.ts function loadCronMutationStore(db, storeKey) { const rows = loadCronRows(db, storeKey); const store = loadedCronStoreFromRows(rows).store; loadCronRuntimeAuthorities({ db, storeKey, jobs: store.jobs }); return { store, jobsFingerprint: fingerprintCronJobRows(rows), runtimeFingerprint: fingerprintCronRuntimeRows(rows) }; } function retireCronMutationTriggerState(db, storeKey, jobId) { const active = findActiveCronRunReceiptInDatabase({ database: db, storePath: storeKey, jobId }); if (active) { retireCronRunTriggerStateInDatabase({ database: db, handle: active }); return; } const job = loadedCronStoreFromRows(loadCronRows(db, storeKey, /* @__PURE__ */ new Set([jobId]))).store.jobs[0]; const startedAtMs = job?.state.runningAtMs; if (!job || startedAtMs === void 0) return; const receiptId = job.state.runningReceiptId ?? findCronRunRecoveryInDatabase({ database: db, jobId, storeKey, startedAt: startedAtMs }).receiptId; if (receiptId) retireCronRunTriggerStateInDatabase({ database: db, handle: { receiptId, storeKey, jobId, startedAtMs } }); } function applyCronReceiptMutation(db, input, nowMs) { const mutation = input.receiptMutation; if (!mutation) return; if (mutation.scheduleChanged) { const nextJob = input.replacement ? input.replacement.store.jobs.find((job) => job.id === mutation.jobId) : input.changes.nextById.get(mutation.jobId); if (!nextJob) throw new Error("Cron schedule mutation has no target job"); if (loadedCronStoreFromRows(loadCronRows(db, input.storeKey, /* @__PURE__ */ new Set([mutation.jobId]))).store.jobs[0]?.state.runningAtMs !== void 0) nextJob.state.runningScheduleChangeId = randomUUID(); else delete nextJob.state.runningScheduleChangeId; } if (mutation.triggerStateChanged) retireCronMutationTriggerState(db, input.storeKey, mutation.jobId); if (mutation.owner) adjudicateActiveCronRunReceiptInDatabase({ database: db, jobId: mutation.jobId, prepared: mutation.owner, finishedAtMs: nowMs }); } function mutateCronJobsInWorker(database, input) { let transactionRefusal; try { return runOpenClawStateWriteTransaction(({ db }) => { try { const receiptSchema = prepareCronRunReceiptWriteSchema(db); const preparation = prepareCronRuntimeMutation("cron.mutateJobs", input.nonce, { deletionBlocked: input.agentId !== void 0 && isAgentDeletionBlocked(input.agentId, {}, db) }); if (input.preconditionJob || input.expectedJob || input.replacement) { const current = loadCronMutationStore(db, input.storeKey); if (input.replacement && (current.jobsFingerprint !== input.replacement.jobsFingerprint || current.runtimeFingerprint !== input.replacement.runtimeFingerprint)) throw new CronJobsStoreChangedError(input.storeKey); const currentById = new Map(current.store.jobs.map((job) => [job.id, job])); const expected = input.expectedJob; const expectedCurrent = expected ? currentById.get(expected.id) : void 0; if (expected && (!expectedCurrent || resolveCronJobConfigRevision(expectedCurrent) !== expected.configRevision)) throw new CronJobsStoreChangedError(input.storeKey); if (input.preconditionJob && !isDeepStrictEqual(structuredClone(currentById.get(input.preconditionJob.id)), input.preconditionJob)) throw new CronJobsStoreChangedError(input.storeKey); if (input.replacement) { for (const [jobId, previous] of input.changes.previousById) { const currentJob = currentById.get(jobId); if (!isDeepStrictEqual(structuredClone(currentJob?.runtimeAuthority), previous.runtimeAuthority) || currentJob?.runtimeAuthorityRecoveryRequired === true !== (previous.runtimeAuthorityRecoveryRequired === true)) throw new CronJobsStoreChangedError(input.storeKey); } assertCronStoreChangesCurrent(input.changes, currentById, input.storeKey); } } const hooks = { receiptSchema, hooks: { beforeWrite: () => { applyCronReceiptMutation(db, input, preparation.nowMs); } } }; if (input.replacement) { for (const jobId of input.changes.changedIds) if (!input.changes.nextById.has(jobId)) deleteCronJobRowInDatabase(db, input.storeKey, jobId); saveCronStoreInDatabase(database, input.storeKey, input.replacement.store, input.replacement.options, hooks); } else saveCronStoreChangesInDatabase(db, input.storeKey, input.storeKey, input.changes, void 0, hooks); const outcome = { ...loadCronMutationStore(db, input.storeKey), names: readCronJobNamesInDatabase(db, void 0, input.storeKey) }; return retainCronRuntimeMutationOutcome("cron.mutateJobs", db, input.nonce, outcome); } catch (error) { if (error instanceof CronJobsStoreChangedError || error instanceof CronRunReceiptConflictError) transactionRefusal = error; throw error; } }, { database, path: database.path, env: getSqliteWorkerStateContext().environment }, { operationLabel: "cron.config-mutation" }); } catch (error) { if (!transactionRefusal || error !== transactionRefusal) throw error; assertTransactionUsable(database.db); if (!database.db.isOpen || database.db.isTransaction) throw error; return { nonce: input.nonce, mutationRefusal: transactionRefusal instanceof CronRunReceiptConflictError ? { kind: "receipt-conflict", receipt: transactionRefusal.receipt } : { kind: "store-changed" } }; } } //#endregion export { mutateCronJobsInWorker };