v1.0.176: spec_events — FOR UPDATE + transaction for seq race

This commit is contained in:
2026-06-24 18:06:05 +04:00
parent cd5ba7470e
commit 0e0939bb32
+18 -4
View File
@@ -1,6 +1,6 @@
"""spec_events — event sourcing: apply ops, reset contract.""" """spec_events — event sourcing: apply ops, reset contract."""
import json, uuid import json, uuid
from .connection import query, execute from .connection import query, execute, get_pool
def reset(contract_id): def reset(contract_id):
@@ -10,11 +10,25 @@ def reset(contract_id):
def get_next_seq(contract_id): def get_next_seq(contract_id):
rows = query( """Get next sequence number with row lock to prevent race conditions."""
"SELECT COALESCE(MAX(seq), 0) + 1 AS n FROM spec_events WHERE contract_id = %s", pool = get_pool()
conn = pool.getconn()
try:
conn.autocommit = False
with conn.cursor() as cur:
cur.execute(
"SELECT COALESCE(MAX(seq), 0) + 1 FROM spec_events WHERE contract_id = %s FOR UPDATE",
(contract_id,), (contract_id,),
) )
return rows[0]["n"] if rows else 1 seq = cur.fetchone()[0]
conn.commit()
return seq
except Exception:
conn.rollback()
raise
finally:
conn.autocommit = True
pool.putconn(conn)
def apply_ops(contract_id, supplement_id, document_id, ops, prompt_id, raw_llm_response): def apply_ops(contract_id, supplement_id, document_id, ops, prompt_id, raw_llm_response):