mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
* perf(state): cap the per-agent SQLite handle cache with LRU eviction Multi-tenant hosts open one WAL database per agent (~3 file descriptors each); the process-local handle cache was unbounded, so large fleets exhausted descriptors. Cache hits now refresh LRU recency, and cache-miss opens evict the oldest non-transactional handle before constructing the new one, capped at 64 open handles. Eviction closes the process-local handle only; registry rows and durable data are untouched and evicted databases reopen transparently on next access. * fix(state): fleet-wide introspection reads stop opening writable agent databases Live testing an 81-agent gateway surfaced three full-fleet sweeps that opened every agent's SQLite database writable (schema ensure + registry write transaction per open): the 60s health snapshot's per-agent session summaries, usage-cost cache reads behind the gateway usage endpoints, and the zalouser doctor detector that ran from every CLI startup. Each sweep churned the new bounded handle cache and saturated the event loop. Session listing gains a readonly non-registering variant (SDK exposes it as an additive readOnly flag on listSessionEntries); health and usage reads use it, with transient-lock tolerance owned by the health caller. The zalouser detector gates on the channel/credentials actually existing, collects once per pass, and detection reads go readonly while migration apply stays writable. The usage refresh queue's flat 50ms busy retry becomes exponential backoff capped at 5s, and refreshing summaries retain their cache timestamp so the 30s TTL gates fleet rescans. * perf(state): make per-agent handle eviction and reopen cheap Eviction only works if reopen is cheap. Reopens after eviction previously repeated full first-open work; ensureOpenClawAgentSchema takes BEGIN IMMEDIATE and the registry upsert writes the shared state DB, so reopens blocked in synchronous busy waits (observed 14-22s event-loop stalls with reconcile workers holding write transactions). Owner/schema validation and registration now run once per path per process with invalidation on quarantine and disposal; the read-only integrity guard still runs on every physical open. Eviction closes with a PASSIVE WAL checkpoint instead of TRUNCATE, which waits on readers; orderly dispose keeps TRUNCATE so sidecars are flushed before unlink. * ci: regenerate plugin-SDK API baseline, drop prod test-seam exports, mock readonly accessor The additive readOnly flag on the SDK listSessionEntries changed the declaration surface, so the generated API baseline is regenerated via the sanctioned script. Knip forbids production exports consumed only by tests: the usage-cache testApi export is removed outright and the refresh-queue seam moves behind an env-gated global exposed by a test-support module. health.plugins.test's full session-accessor mock gains the newly imported readonly listing.