fix(storage): reuse connection per decision cycle - #656
Conversation
|
Thanks @be-student, the shape here is right: one open per decision instead of twelve, helpers still safe on their own, and a failed setup still fails closed. One thing has to change before I can take it. decide_and_execute now wraps the whole cycle in open_db, and the AUTH challenge inside that cycle runs the prompter on a worker thread through contextvars.copy_context() (challenge.py:410), so the task-local connection travels into that thread. The worker then calls asyncio.run(...) for approval memory and dashboard polling (challenge.py:144, dashboard_prompter.py:103 and 118), and open_db inside those loops hands back the outer loop's aiosqlite connection. An aiosqlite connection belongs to one loop and one thread, and a worker that outlives its join sees ValueError('no active connection') once the outer scope closes it. I reproduced both: the same connection object reused across the thread and a new loop, and the late-worker error. The fix I'd take: keep the reuse for the decision path but make the challenge worker start with _ACTIVE_DB unset (reset it in the worker, or scope open_db to the parts before and after the challenge), plus a test that a challenge worker never sees the outer connection. Your call on which. Ping me when it's pushed. |
|
Thanks @be-student, holding this one. The shared connection reaches the AUTH path through |
Pull Request
Slice
What this PR does
Wraps each proxy decision in a task-local SQLite connection scope. Nested storage helpers reuse that connection, while standalone calls, other repositories, and concurrent decisions keep independent lifecycles.
Tests added (run in CI)
call_tool()uses one physical connection.Changelog
changelog.d/<PR>.fixed.mdfragment added in the follow-up commitPublic-release safety (doberman-core only)
Security checklist
Edge cases covered / Deviations from plan / Risks introduced
Closes #597