mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(release): commit the approve() COMPLETED write under the release lock
approve() flushed the published proposal's COMPLETED status but left the durable commit to the background caller (_run_approve_background), which runs after approve()'s finally has already released the Redis lock. In that window a concurrent reject() could acquire the freed lock, re-read a row whose COMPLETED write was only flushed (invisible to its own session under READ COMMITTED), pass its guard, and flip the just-published proposal to CANCELLED — last writer winning the row. The bug-sweep (#638) fixed reject()'s side of this but left approve()'s, so reject()'s 'fails closed' guarantee didn't hold end to end. Commit COMPLETED while still holding the lock (mirroring XPostService._post), so it's durable before release and a racing reject sees it and refuses. A cross-session regression test proves a fresh connection sees COMPLETED the moment approve returns (it read 'pending' before the fix).
This commit is contained in:
@@ -31,6 +31,7 @@ def _task(*, source: str = "release_manager") -> MagicMock:
|
||||
def _session() -> MagicMock:
|
||||
s = MagicMock()
|
||||
s.flush = AsyncMock()
|
||||
s.commit = AsyncMock()
|
||||
return s
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user