Merge pull request #2111 from pikasTech/fix/2109-db-write-readiness

fix: 分离 Postgres 写入 readiness 与 durable read readiness
This commit is contained in:
Lyon
2026-06-25 10:46:45 +08:00
committed by GitHub
2 changed files with 39 additions and 2 deletions
+33
View File
@@ -966,6 +966,37 @@ test("configured postgres runtime allocates Workbench projectedSeq idempotently
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("SELECT pg_advisory_xact_lock")));
});
test("configured postgres runtime writes Workbench facts without re-running blocked read readiness", async () => {
const queryClient = createFakePostgresClient({ migrationReady: true, countErrorCode: "53300" });
const store = createConfiguredCloudRuntimeStore({
env: {
HWLAB_CLOUD_RUNTIME_ADAPTER: "postgres",
HWLAB_CLOUD_RUNTIME_DURABLE: "true"
},
dbUrl: "postgres://hwlab_redacted@db.example.invalid:5432/hwlab",
queryClient,
now: () => "2026-06-25T02:50:00.000Z"
});
const readiness = await store.readiness();
assert.equal(readiness.blocker, RUNTIME_DURABLE_ADAPTER_QUERY_BLOCKED);
assert.equal(readiness.connection.queryResult, "query_blocked");
queryClient.calls.length = 0;
const write = await store.writeWorkbenchFacts({
facts: {
sessions: [{ sessionId: "ses_write_after_read_blocked", ownerUserId: "usr_write_after_read_blocked", status: "running", updatedAt: "2026-06-25T02:50:01.000Z" }]
}
});
assert.equal(write.written, true);
assert.equal(queryClient.calls.filter((call) => isReadinessQuery(call.sql)).length, 0);
assert.equal(queryClient.calls.some((call) => call.sql.startsWith("CREATE INDEX IF NOT EXISTS")), false);
assert.ok(queryClient.calls.some((call) => call.sql === "BEGIN"));
assert.ok(queryClient.calls.some((call) => call.sql === "COMMIT"));
assert.ok(queryClient.calls.some((call) => call.sql.startsWith("INSERT INTO workbench_sessions")));
});
test("configured postgres runtime reuses proven readiness for Workbench durable reads", async () => {
const queryClient = createFakePostgresClient({ migrationReady: true });
const store = createConfiguredCloudRuntimeStore({
@@ -982,6 +1013,7 @@ test("configured postgres runtime reuses proven readiness for Workbench durable
sessions: [{ sessionId: "ses_ready_cached", ownerUserId: "usr_ready", status: "running", updatedAt: "2026-06-20T10:00:01.000Z" }]
}
});
await store.readiness();
queryClient.calls.length = 0;
const first = await store.queryWorkbenchFacts({ families: ["sessions"], limit: 10 });
@@ -1029,6 +1061,7 @@ test("configured postgres runtime can query thin Workbench session summaries", a
}]
}
});
await store.readiness();
queryClient.calls.length = 0;
const loaded = await store.queryWorkbenchFacts({ families: ["sessions"], sessionProjection: "summary", limit: 10 });
+6 -2
View File
@@ -1533,8 +1533,12 @@ export class PostgresCloudRuntimeStore {
}
async assertReadyForWrites() {
const readiness = await this.readiness();
if (readiness.ready !== true) {
if (!this.dbUrl && !this.queryClient) {
const readiness = this.blockedSummary({
blocker: RUNTIME_DURABLE_ADAPTER_UNCONFIGURED,
reason: "Postgres runtime adapter is selected but HWLAB_CLOUD_DB_URL is not injected"
});
this.lastReadiness = readiness;
throw new HwlabProtocolError("Postgres durable runtime adapter is not ready for writes", {
code: ERROR_CODES.internalError,
data: {