Commit 46f7691
committed
feat: Implement MainEventBus architecture and resolve multi-instance replication race conditions
Introduce centralized event bus with single background processor to guarantee
events persist to TaskStore before distribution to clients. This eliminates race
conditions when multiple concurrent requests update the same task.
**Key Components:**
- MainEventBus: Shared BlockingQueue for all MainQueue events
- MainEventBusProcessor: Single background thread for ordered processing
- Processing sequence: TaskStore.save() → PushNotifications → distributeToChildren()
- TaskStateProvider interface: Task state queries for queue lifecycle management
**Event Flow:**
```
AgentExecutor → MainQueue → MainEventBus → MainEventBusProcessor
→ TaskStore (persist first) → Push Notifications → ChildQueues → Clients
```
**Benefits:**
- Events persist before clients receive them (no stale data)
- Serial processing prevents concurrent TaskStore updates
- Platform-agnostic ChildQueue synchronization (works across gRPC/JSONRPC/REST)
- Clean separation: MainQueue (no local queue) vs ChildQueue (local queue for clients)
Implement two-level protection to keep MainQueues open for fire-and-forget tasks
and late resubscriptions while cleaning up finalized tasks:
**Level 1** - Cleanup Callback: Check TaskStateProvider.isTaskFinalized() before
removing queue from QueueManager map
**Level 2** - Auto-Close Prevention: MainQueue.childClosing() checks finality before
closing when last ChildQueue disconnects
**Result:** Non-final tasks keep queues open for resubscription; finalized tasks
clean up immediately
ReplicatedQueueManager.onTaskFinalized() sent full Task objects to remote instances
via Kafka, while local instances sent TaskStatusUpdateEvent. Client auto-close logic
only checked for TaskStatusUpdateEvent.isFinal(), causing connection leaks on remote
instances.
**ReplicatedQueueManager.onTaskFinalized():** Convert Task to TaskStatusUpdateEvent
before sending to Kafka, ensuring consistent event types across all instances
**EventConsumer:** Add 50ms delay before tube.complete() to allow SSE buffer flush
in replicated scenarios where events arrive via Kafka with timing variations
**SSEEventListener (JSONRPC):** Check both TaskStatusUpdateEvent.isFinal() and
Task.status().state().isFinal() for auto-close
**RestSSEEventListener (REST):** Add complete auto-close logic (was missing entirely)
**Benefits:**
- Handles late subscriptions to completed tasks gracefully
- Prevents connection leaks in all scenarios
- Consistent behavior across JSONRPC and REST transports
- Defensive programming for edge cases
**MultiInstanceReplicationTest:**
- Add TaskEvent handling and container log dumping on failure
- Verify both APP1 and APP2 receive all events including final states
- Test late-arriving replicated events and poison pill ordering
**Integration Tests:**
- EventConsumerTest: Grace period mechanism for replicated scenarios
- ReplicatedQueueManagerTest: Event type conversion validation
- All existing tests updated for MainEventBus architecture
**EventQueue.Builder:** Now requires MainEventBus parameter (validates non-null)
**QueueManager Implementations:** Must handle TaskStateProvider for lifecycle checks
Existing code continues to work - InMemoryQueueManager and ReplicatedQueueManager
automatically inject MainEventBus via CDI. Custom QueueManager implementations
should inject MainEventBus and pass to EventQueue.Builder.
**Core Architecture:**
- server-common/.../events/MainEventBus.java (new)
- server-common/.../events/MainEventBusProcessor.java (new)
- server-common/.../events/EventQueue.java (requires MainEventBus)
- server-common/.../events/InMemoryQueueManager.java (queue lifecycle)
**Replication:**
- extras/queue-manager-replicated/core/.../ReplicatedQueueManager.java (event conversion)
- extras/queue-manager-replicated/core/.../ReplicatedEventQueueItem.java (Task support)
**Client Transports:**
- client/transport/jsonrpc/.../SSEEventListener.java (enhanced auto-close)
- client/transport/rest/.../RestSSEEventListener.java (add auto-close)
**Event Processing:**
- server-common/.../events/EventConsumer.java (grace period + buffer flush)
- server-common/.../requesthandlers/DefaultRequestHandler.java (MainEventBus integration)
**Task Management:**
- server-common/.../tasks/TaskStore.java (TaskStateProvider interface)
- extras/task-store-database-jpa/.../JpaDatabaseTaskStore.java (implement TaskStateProvider)
✅ All unit tests pass (150+ tests)
✅ MultiInstanceReplicationTest passes (both instances receive all events)
✅ TCK tests pass (no connection leaks)
✅ Integration tests pass (EventConsumer, QueueManager, TaskStore)1 parent 659df81 commit 46f7691
56 files changed
Lines changed: 3236 additions & 2210 deletions
File tree
- client/transport
- jsonrpc/src/main/java/io/a2a/client/transport/jsonrpc/sse
- rest/src/main/java/io/a2a/client/transport/rest/sse
- examples/cloud-deployment/scripts
- extras
- common/src/main/java/io/a2a/extras/common/events
- push-notification-config-store-database-jpa/src/main/java/io/a2a/extras/pushnotificationconfigstore/database/jpa
- queue-manager-replicated
- core/src
- main/java/io/a2a/extras/queuemanager/replicated/core
- test/java/io/a2a
- extras/queuemanager/replicated/core
- server/events
- tests-multi-instance
- quarkus-app-1/src/main/resources
- quarkus-app-2/src/main/resources
- tests/src/test/java/io/a2a/extras/queuemanager/replicated/tests/multiinstance
- tests-single-instance/src/test/java/io/a2a/extras/queuemanager/replicated/tests
- task-store-database-jpa/src
- main/java/io/a2a/extras/taskstore/database/jpa
- test/java/io/a2a/extras/taskstore/database/jpa
- reference
- jsonrpc/src
- main/java/io/a2a/server/apps/quarkus
- test/resources
- rest/src/main/java/io/a2a/server/rest/quarkus
- server-common/src
- main
- java/io/a2a/server
- events
- requesthandlers
- tasks
- util
- async
- sse
- resources/META-INF
- test/java/io/a2a/server
- events
- requesthandlers
- tasks
- tck/src/main/resources
- tests/server-common/src/test/java/io/a2a/server/apps/common
- transport
- grpc/src
- main/java/io/a2a/transport/grpc/handler
- test/java/io/a2a/transport/grpc/handler
- jsonrpc/src/test/java/io/a2a/transport/jsonrpc/handler
- rest/src
- main/java/io/a2a/transport/rest/handler
- test/java/io/a2a/transport/rest/handler
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 17 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
13 | 15 | | |
14 | 16 | | |
15 | 17 | | |
| |||
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
67 | | - | |
68 | | - | |
69 | | - | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
70 | 80 | | |
71 | 81 | | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
72 | 86 | | |
73 | 87 | | |
74 | 88 | | |
| |||
Lines changed: 22 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
13 | 16 | | |
14 | 17 | | |
15 | 18 | | |
| |||
29 | 32 | | |
30 | 33 | | |
31 | 34 | | |
32 | | - | |
| 35 | + | |
33 | 36 | | |
34 | 37 | | |
35 | 38 | | |
| |||
44 | 47 | | |
45 | 48 | | |
46 | 49 | | |
47 | | - | |
| 50 | + | |
48 | 51 | | |
49 | 52 | | |
50 | 53 | | |
| |||
62 | 65 | | |
63 | 66 | | |
64 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
65 | 85 | | |
66 | 86 | | |
67 | 87 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
212 | 212 | | |
213 | 213 | | |
214 | 214 | | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
215 | 231 | | |
216 | 232 | | |
217 | 233 | | |
| |||
Lines changed: 10 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
8 | | - | |
9 | | - | |
| 8 | + | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | | - | |
| 15 | + | |
15 | 16 | | |
| 17 | + | |
16 | 18 | | |
17 | 19 | | |
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
21 | 23 | | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
22 | 28 | | |
23 | 29 | | |
24 | | - | |
| 30 | + | |
25 | 31 | | |
26 | 32 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
167 | 168 | | |
Lines changed: 10 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
152 | 162 | | |
153 | 163 | | |
154 | 164 | | |
| |||
Lines changed: 69 additions & 34 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
| 19 | + | |
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
| |||
45 | 47 | | |
46 | 48 | | |
47 | 49 | | |
48 | | - | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
49 | 53 | | |
50 | 54 | | |
51 | | - | |
| 55 | + | |
52 | 56 | | |
53 | 57 | | |
54 | 58 | | |
| |||
77 | 81 | | |
78 | 82 | | |
79 | 83 | | |
80 | | - | |
81 | | - | |
| 84 | + | |
82 | 85 | | |
83 | 86 | | |
84 | 87 | | |
| |||
87 | 90 | | |
88 | 91 | | |
89 | 92 | | |
90 | | - | |
91 | | - | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
92 | 96 | | |
| 97 | + | |
93 | 98 | | |
94 | 99 | | |
95 | 100 | | |
96 | 101 | | |
97 | 102 | | |
98 | 103 | | |
99 | 104 | | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
108 | | - | |
109 | | - | |
110 | | - | |
111 | | - | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
118 | 131 | | |
119 | 132 | | |
120 | 133 | | |
121 | 134 | | |
122 | 135 | | |
123 | | - | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
124 | 141 | | |
125 | | - | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
126 | 148 | | |
127 | 149 | | |
128 | 150 | | |
129 | | - | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
130 | 166 | | |
131 | | - | |
| 167 | + | |
132 | 168 | | |
133 | 169 | | |
134 | 170 | | |
| |||
152 | 188 | | |
153 | 189 | | |
154 | 190 | | |
155 | | - | |
156 | | - | |
157 | | - | |
158 | | - | |
159 | | - | |
160 | | - | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
161 | 196 | | |
162 | 197 | | |
163 | 198 | | |
| |||
0 commit comments