黄云龙 8be7411da8
fix(runtime): serialize SQLite event-store writes to prevent per-thread seq collisions (#4077)
* fix(run-events): serialize seq assignment with a per-thread asyncio lock

put() and put_batch() read max(seq) and then INSERT seq+1 in separate awaits.
Two coroutines writing the same thread in one process could interleave
between the read and the insert and assign the same seq, colliding on
SQLite where the DB-level FOR UPDATE lock is weaker than Postgres. Add a
per-thread asyncio.Lock (_write_locks / _get_write_lock) around the
read-assign-insert critical section in both methods.

* address review: evict orphaned per-thread write-lock in delete_by_thread

_write_locks accumulated one asyncio.Lock per thread ever seen and never
released, leaking in the long-lived DbRunEventStore singleton. Evict the
entry after delete_by_thread when no writer holds it (lock recreated
lazily on the next write). Per @willem-bd review on #4077.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-12 13:03:02 +08:00
..
2026-07-07 14:39:04 +08:00