fix(a2a/events): guard A2aEventQueue with threading.Lock to prevent concurrent iteration crash #8256

Merged
HAL9000 merged 4 commits from fix/issue-7604-a2a-event-queue-concurrency into master 2026-06-17 22:40:59 +00:00

4 Commits

Author SHA1 Message Date
controller-ci-rerun 799084e396 chore: re-trigger CI [controller]
CI / load-versions (pull_request) Successful in 16s
CI / push-validation (pull_request) Successful in 28s
CI / quality (pull_request) Successful in 51s
CI / lint (pull_request) Successful in 1m2s
CI / security (pull_request) Successful in 1m18s
CI / typecheck (pull_request) Successful in 1m20s
CI / build (pull_request) Successful in 29s
CI / helm (pull_request) Successful in 43s
CI / unit_tests (pull_request) Successful in 4m36s
CI / docker (pull_request) Successful in 1m29s
CI / integration_tests (pull_request) Successful in 10m14s
CI / coverage (pull_request) Successful in 9m28s
CI / status-check (pull_request) Successful in 3s
CI / load-versions (push) Successful in 12s
CI / push-validation (push) Successful in 25s
CI / build (push) Successful in 40s
CI / lint (push) Successful in 51s
CI / quality (push) Successful in 1m0s
CI / helm (push) Successful in 55s
CI / typecheck (push) Successful in 1m10s
CI / security (push) Successful in 1m18s
CI / unit_tests (push) Successful in 4m42s
CI / docker (push) Failing after 15m56s
CI / coverage (push) Failing after 15m59s
CI / integration_tests (push) Failing after 21m34s
CI / status-check (push) Has been cancelled
CI / benchmark-publish (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
2026-06-17 18:24:32 -04:00
controller-ci-rerun 8e8702456e chore: re-trigger CI [controller] 2026-06-17 18:24:32 -04:00
controller-ci-rerun a3956ca5e1 chore: re-trigger CI [controller] 2026-06-17 18:24:32 -04:00
HAL9000 3dc22f4630 fix(a2a/events): guard A2aEventQueue with threading.Lock to prevent concurrent iteration crash
Fix a critical concurrency bug in A2aEventQueue.publish() where the method
iterates over _subscriptions without holding a lock. This causes RuntimeError:
dictionary changed size during iteration when subscribe_local/unsubscribe are
called concurrently from other threads.

The fix introduces a threading.Lock to protect all state mutations and
dictionary access in the A2aEventQueue class, while carefully ensuring callbacks
are invoked outside the lock to prevent potential deadlocks.

Changes:
- src/cleveragents/a2a/events.py: Added _lock attribute, protected
  __init__, is_closed, publish, subscribe_local, unsubscribe, get_events,
  and close methods with threading.Lock snapshot pattern for callbacks.

- features/a2a_event_queue_concurrency.feature: BDD feature file with 6
  scenarios covering concurrent publish/subscribe/unsubscribe safety.

- features/steps/a2a_event_queue_concurrency_steps.py: Step definitions
  implementing multi-threaded concurrency test harness.

ISSUES CLOSED: #7604
2026-06-17 18:24:32 -04:00