fix(robomp): serialized same-issue event claims

Prevented the durable queue from claiming a queued event while another event with the same issue key is still running, so duplicate worker instances cannot resume the same RpcClient session concurrently.

Added regression coverage for blocked same-issue events and for skipping blocked queue heads without stalling unrelated issues.

Fixes #1840
This commit is contained in:
roboomp
2026-06-04 10:48:35 +00:00
parent f6fca1f5cd
commit d5eb9caacf
2 changed files with 79 additions and 6 deletions
+19 -6
View File
@@ -50,6 +50,9 @@ CREATE TABLE IF NOT EXISTS events (
CREATE INDEX IF NOT EXISTS events_state_received
ON events(state, received_at);
CREATE INDEX IF NOT EXISTS events_issue_state
ON events(issue_key, state);
CREATE TABLE IF NOT EXISTS issues (
key TEXT PRIMARY KEY,
repo TEXT NOT NULL,
@@ -293,15 +296,25 @@ class Database:
return cur.rowcount > 0
def claim_next_event(self) -> EventRow | None:
"""Atomically dequeue one queued event into running state."""
"""Atomically dequeue one unblocked queued event into running state."""
with self._txn() as conn:
row = conn.execute(
"""
SELECT delivery_id, event_type, repo, issue_key, payload_json, received_at,
state, attempts, last_error
FROM events
WHERE state = 'queued'
ORDER BY received_at
SELECT queued.delivery_id, queued.event_type, queued.repo, queued.issue_key,
queued.payload_json, queued.received_at, queued.state, queued.attempts,
queued.last_error
FROM events AS queued
WHERE queued.state = 'queued'
AND (
queued.issue_key IS NULL
OR NOT EXISTS (
SELECT 1
FROM events AS running
WHERE running.state = 'running'
AND running.issue_key = queued.issue_key
)
)
ORDER BY queued.received_at
LIMIT 1
"""
).fetchone()