mirror of
https://github.com/openclaw/openclaw.git
synced 2026-09-28 22:15:22 +08:00
fix(state): retire workers after existing-schema scope ends
The reuse guard added in e52420e1ee validates a cached worker's original
read admission. Ending a managed existing-schema scope threw a plain Error,
so the guard propagated it instead of retiring an idle worker before an
ordinary open on the same database.
Classify ended schema scopes as StateDatabaseReadAdmissionInvalidatedError
at the schema-policy owner, retaining the diagnostic message. The existing
guard now joins idle actor retirement; active actors remain refused and
unrelated admission or cleanup failures still propagate. Strengthen the
existing expired-caller assertion to require the invalidation code.
No schema, retention, permission, or update-driver contract changes.
Reproduced the existing-schema test on main: 1 failed, 1 passed before fix.
Focused schema/worker suites: 25/25. Changed two-test file: 2/2 in 15.06s
Vitest time, 30.15s wrapper wall with one worker; no new fixtures or cases.
Linux Node 24.19.0: all 39 requested sqlite/state worker and caller-mode
files passed 405 tests; reconstructed CI shard 19 passed 913 tests across
45 files in 221.57s. Native Blacksmith Testbox command exited 0:
https://github.com/openclaw/openclaw/actions/runs/36329004971
Core tsgo, infra/state test graphs, changed-file lint/format, import-cycle
check, diff check, and independent Codex P2 autoreview passed.
This commit is contained in:
@@ -100,6 +100,9 @@ path; active work must settle before replacement. This prevents Doctor and plugi
|
||||
migrations from recreating retired database paths or acquiring leases in the wrong
|
||||
database. Existing update drivers and stored schemas need no migration.
|
||||
|
||||
Completion of a managed existing-schema scope also revokes its read admission.
|
||||
Ordinary callers reopen through normal schema admission after the idle actor retires.
|
||||
|
||||
Each SQLite broker worker admits up to 128 running and queued requests. A busy
|
||||
worker's admission queue does not consume another worker's request capacity;
|
||||
independent workers continue serving their databases. Requests on the same worker
|
||||
|
||||
@@ -96,7 +96,10 @@ describe("existing-schema shared-state workers", () => {
|
||||
type: "flows.list",
|
||||
input: { ownerKey: "agent:main:expired" },
|
||||
}),
|
||||
).rejects.toThrow("schema admission has ended");
|
||||
).rejects.toMatchObject({
|
||||
code: "STATE_DATABASE_READ_ADMISSION_INVALIDATED",
|
||||
message: "Existing shared-state schema admission has ended.",
|
||||
});
|
||||
expect(readAppVersion(databasePath)).toBe("synthetic-installed-runtime");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { DatabaseSync } from "node:sqlite";
|
||||
import { isPromiseLike } from "@openclaw/normalization-core/promise-like";
|
||||
import { hasErrnoCode } from "../infra/errno.js";
|
||||
import { resolveGlobalSingleton } from "../shared/global-singleton.js";
|
||||
import { StateDatabaseReadAdmissionInvalidatedError } from "./openclaw-state-db-async-lifecycle.js";
|
||||
|
||||
type ExistingSchemaScope = { path: string; canonicalPath: string; active: boolean };
|
||||
const schemaPolicies = resolveGlobalSingleton(
|
||||
@@ -64,7 +65,9 @@ export function withExistingOpenClawStateSchema<T>(
|
||||
|
||||
function assertSchemaScopeActive(scope: ExistingSchemaScope | undefined): void {
|
||||
if (scope && !scope.active) {
|
||||
throw new Error("Existing shared-state schema admission has ended.");
|
||||
throw new StateDatabaseReadAdmissionInvalidatedError(
|
||||
"Existing shared-state schema admission has ended.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user