Skip to content

Commit 088bc77

Browse files
committed
fix(server): cover builder-based manual processor startup
1 parent 4b6eac7 commit 088bc77

4 files changed

Lines changed: 37 additions & 8 deletions

File tree

‎docs/content/dev/server.md‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,17 +266,32 @@ class A2AServerConfiguration {
266266
return new MainEventBusProcessor(mainEventBus, taskStore, pushSender, queueManager);
267267
}
268268

269+
@Bean(destroyMethod = "shutdown")
270+
ExecutorService a2aEventConsumerExecutor() {
271+
return Executors.newCachedThreadPool();
272+
}
273+
269274
@Bean
270275
RequestHandler requestHandler(AgentExecutor agentExecutor, TaskStore taskStore,
271276
QueueManager queueManager, PushNotificationConfigStore pushConfigStore,
272277
MainEventBusProcessor mainEventBusProcessor,
273-
@Qualifier("a2aInternal") Executor executor) {
274-
return new DefaultRequestHandler(agentExecutor, taskStore, queueManager, pushConfigStore,
275-
mainEventBusProcessor, executor, executor);
278+
TaskAuthorizationProvider authorizationProvider,
279+
@Qualifier("a2aInternalExecutor") Executor executor,
280+
@Qualifier("a2aEventConsumerExecutor") Executor eventConsumerExecutor) {
281+
return DefaultRequestHandler.builder()
282+
.agentExecutor(agentExecutor)
283+
.taskStore(taskStore)
284+
.queueManager(queueManager)
285+
.pushConfigStore(pushConfigStore)
286+
.mainEventBusProcessor(mainEventBusProcessor)
287+
.authorizationProvider(authorizationProvider)
288+
.executor(executor)
289+
.eventConsumerExecutor(eventConsumerExecutor)
290+
.build();
276291
}
277292
}
278293
```
279294

280-
This assumes the other method parameters are also registered as Spring beans. The same executor is passed for agent execution and event consumption, as in this example; applications can provide separate executors when needed.
295+
Register the remaining dependencies, including an `a2aInternalExecutor` bean and a `TaskAuthorizationProvider`, as Spring beans. Keep the cached event consumer executor separate from the agent executor: blocking event polling can exhaust a bounded pool under load.
281296

282297
See [CONTRIBUTING_INTEGRATIONS.md](https://github.com/a2aproject/a2a-java/blob/main/CONTRIBUTING_INTEGRATIONS.md) to submit your own integration.

‎server-common/src/main/java/org/a2aproject/sdk/server/events/MainEventBusProcessor.java‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ int pushNotificationChainCount() {
156156
return pushNotificationChains.size();
157157
}
158158

159+
/**
160+
* Starts the background processor thread if it is not already running.
161+
*/
159162
@SuppressWarnings("NullAway.Init")
160163
@PostConstruct
161164
public synchronized void start() {

‎server-common/src/main/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandler.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@ protected DefaultRequestHandler() {
308308
this.eventConsumerExecutor = null;
309309
}
310310

311+
/**
312+
* Constructor used by CDI to create the request handler. Its signature may change between
313+
* releases; application code should use {@link #builder()} to configure and create a handler.
314+
*/
311315
@Inject
312316
public DefaultRequestHandler(AgentExecutor agentExecutor, TaskStore taskStore,
313317
QueueManager queueManager, PushNotificationConfigStore pushConfigStore,

‎server-common/src/test/java/org/a2aproject/sdk/server/requesthandlers/DefaultRequestHandlerTest.java‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ void testInitConfigReadsBlockingTimeouts() {
187187
}
188188

189189
@Test
190-
void testConstructorStartsManuallyConstructedMainEventBusProcessor() throws Exception {
190+
void testBuilderStartsManuallyConstructedMainEventBusProcessor() throws Exception {
191191
InMemoryTaskStore manualTaskStore = new InMemoryTaskStore();
192192
PushNotificationConfigStore manualPushConfigStore = new InMemoryPushNotificationConfigStore();
193193
MainEventBus manualMainEventBus = new MainEventBus();
@@ -207,9 +207,16 @@ public void cancel(RequestContext context, AgentEmitter agentEmitter) {
207207
throw new AssertionError("Cancel should not be invoked");
208208
}
209209
};
210-
DefaultRequestHandler manualRequestHandler = new DefaultRequestHandler(
211-
manualAgentExecutor, manualTaskStore, manualQueueManager, manualPushConfigStore,
212-
manualProcessor, internalExecutor, internalExecutor);
210+
DefaultRequestHandler manualRequestHandler = DefaultRequestHandler.builder()
211+
.agentExecutor(manualAgentExecutor)
212+
.taskStore(manualTaskStore)
213+
.queueManager(manualQueueManager)
214+
.pushConfigStore(manualPushConfigStore)
215+
.mainEventBusProcessor(manualProcessor)
216+
.executor(internalExecutor)
217+
.eventConsumerExecutor(internalExecutor)
218+
.authorizationRequired(false)
219+
.build();
213220
manualRequestHandler.agentCompletionTimeoutSeconds = 5;
214221
manualRequestHandler.consumptionCompletionTimeoutSeconds = 2;
215222
manualRequestHandler.reconciliationTimeoutSeconds = 1;

0 commit comments

Comments
 (0)