Skip to content

fix(spring): bind the agent executor pool by bean name, not by type - #99

Merged
guofei66 merged 1 commit into
project-openan:mainfrom
tangzhiqiang:fix/a2a-agent-executor-pool-qualifier
Oct 22, 2026
Merged

guofei66 merged 1 commit into
project-openan:mainfrom
tangzhiqiang:fix/a2a-agent-executor-pool-qualifier

Conversation

@tangzhiqiang

Copy link
Copy Markdown
Contributor

Fixes #98

Summary

  • Match the A2A server executor by bean name: @Bean(name = "agentExecutorPool") + @ConditionalOnMissingBean(name = "agentExecutorPool")
  • Qualify both injection points with @Qualifier("agentExecutorPool") (requestHandler parameter 5 and restHandler)

Why

The bare @ConditionalOnMissingBean matched by return type (ExecutorService), so any host executor bean suppressed the pool; the handlers then injected ExecutorService by type and failed with NoUniqueBeanDefinitionException at parameter 5 of requestHandler.

Behaviour

  • Host defines unrelated ExecutorService/ScheduledExecutorService beans: the starter still creates agentExecutorPool and both handlers wire to it.
  • Host defines its own bean named agentExecutorPool: the auto-configuration backs off and the handlers use the host bean.
  • Capacity still comes from the existing a2at.server.executor-* properties.

Verification

  • mvn -pl spring-boot-starter test: 32 tests pass
  • New WebApplicationContextRunner regression test with two foreign ExecutorService/ScheduledExecutorService beans - reproduced the reported NoUniqueBeanDefinitionException before the fix, passes after
  • Host-override test: a host bean named agentExecutorPool replaces the auto-configured one
  • mvn -pl spring-boot-starter spotless:check passes

agentExecutorPool used a bare @ConditionalOnMissingBean, which matches by
return type (ExecutorService). Host applications routinely define their own
ExecutorService beans - dispatchers, ScheduledExecutorService-based SSE
heartbeat schedulers, pub-sub workers - and because user configuration
registers before auto-configuration, any one of them suppressed the A2A
pool. requestHandler and restHandler then injected ExecutorService by type
without a qualifier, found several candidates (none primary), and the
application failed to refresh with NoUniqueBeanDefinitionException at
"Parameter 5 of method requestHandler".

Match by bean name instead: the pool is always auto-configured unless the
host declares its own bean named agentExecutorPool, and both injection
points take @qualifier("agentExecutorPool"). Capacity keeps coming from
the a2at.server.executor-* properties.

Regression: a WebApplicationContextRunner with foreign ExecutorService and
ScheduledExecutorService beans pre-registered now starts and wires the
auto-configured pool (verified to reproduce the reported
NoUniqueBeanDefinitionException without the fix), plus a host-override
test where a same-named bean replaces the auto-configured one.

Signed-off-by: tangzhiqiang <tangzhiqiang@gdcattsoft.com>
@tangzhiqiang
tangzhiqiang requested a review from a team as a code owner October 22, 2026 10:29
@tangzhiqiang

Copy link
Copy Markdown
Contributor Author

@guofei66 could you take a look and merge when convenient? CI is green on 86eb027. The change is scoped to A2AAutoConfiguration (bean-name condition + @Qualifier) plus two regression tests.

@guofei66
guofei66 merged commit 168a7cb into project-openan:main Oct 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(spring): host ExecutorService beans break A2AAutoConfiguration startup

2 participants