Skip to content

Commit 1b31744

Browse files
committed
feat!: Remove hard dependency on MicroProfile Config from the core SDK (#468)
Default values will now be used by default. You can supply your own by providing a CDI bean with a higher priority. Also, there is a new 2a-java-sdk-microprofile-config with the previous MicroProfile Config capabilities. If used, this will allow MicroProfile Config configurations of the properties. The reference implementations use this new module Fixes #467 🦕
1 parent 003a67b commit 1b31744

File tree

16 files changed

+666
-35
lines changed

16 files changed

+666
-35
lines changed

README.md

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,22 @@ public class WeatherAgentExecutorProducer {
232232
}
233233
```
234234

235-
### 4. Configure Executor Settings (Optional)
235+
### 4. Configuration System
236236

237-
The A2A Java SDK uses a dedicated executor for handling asynchronous operations like streaming subscriptions. By default, this executor is configured with a core pool size of 5 threads and a maximum pool size of 50 threads, optimized for I/O-bound operations.
237+
The A2A Java SDK uses a flexible configuration system that works across different frameworks.
238238

239-
You can customize the executor settings in your `application.properties`:
239+
**Default behavior:** Configuration values come from `META-INF/a2a-defaults.properties` files on the classpath (provided by core modules and extras). These defaults work out of the box without any additional setup.
240+
241+
**Customizing configuration:**
242+
- **Quarkus/MicroProfile Config users**: Add the [`microprofile-config`](integrations/microprofile-config/README.md) integration to override defaults via `application.properties`, environment variables, or system properties
243+
- **Spring/other frameworks**: See the [integration module README](integrations/microprofile-config/README.md#custom-config-providers) for how to implement a custom `A2AConfigProvider`
244+
- **Reference implementations**: Already include the MicroProfile Config integration
245+
246+
#### Configuration Properties
247+
248+
**Executor Settings** (Optional)
249+
250+
The SDK uses a dedicated executor for async operations like streaming. Default: 5 core threads, 50 max threads.
240251

241252
```properties
242253
# Core thread pool size for the @Internal executor (default: 5)
@@ -249,20 +260,23 @@ a2a.executor.max-pool-size=50
249260
a2a.executor.keep-alive-seconds=60
250261
```
251262

252-
**Why this matters:**
253-
- **Streaming Performance**: The executor handles streaming subscriptions. Too few threads can cause timeouts under concurrent load.
254-
- **Resource Management**: The dedicated executor prevents streaming operations from competing with the ForkJoinPool used by other async tasks.
255-
- **Concurrency**: In production environments with high concurrent streaming requests, increase the pool sizes accordingly.
263+
**Blocking Call Timeouts** (Optional)
256264

257-
**Default Configuration:**
258265
```properties
259-
# These are the defaults - no need to set unless you want different values
260-
a2a.executor.core-pool-size=5
261-
a2a.executor.max-pool-size=50
262-
a2a.executor.keep-alive-seconds=60
266+
# Timeout for agent execution in blocking calls (default: 30 seconds)
267+
a2a.blocking.agent.timeout.seconds=30
268+
269+
# Timeout for event consumption in blocking calls (default: 5 seconds)
270+
a2a.blocking.consumption.timeout.seconds=5
263271
```
264272

265-
**Note:** The reference server implementations automatically configure this executor. If you're creating a custom server integration, ensure you provide an `@Internal Executor` bean for optimal streaming performance.
273+
**Why this matters:**
274+
- **Streaming Performance**: The executor handles streaming subscriptions. Too few threads can cause timeouts under concurrent load.
275+
- **Resource Management**: The dedicated executor prevents streaming operations from competing with the ForkJoinPool.
276+
- **Concurrency**: In production with high concurrent streaming, increase pool sizes accordingly.
277+
- **Agent Timeouts**: LLM-based agents may need longer timeouts (60-120s) compared to simple agents.
278+
279+
**Note:** The reference server implementations (Quarkus-based) automatically include the MicroProfile Config integration, so properties work out of the box in `application.properties`.
266280

267281
## A2A Client
268282

extras/task-store-database-jpa/src/main/java/io/a2a/extras/taskstore/database/jpa/JpaDatabaseTaskStore.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.time.Duration;
44
import java.time.Instant;
55

6+
import jakarta.annotation.PostConstruct;
67
import jakarta.annotation.Priority;
78
import jakarta.enterprise.context.ApplicationScoped;
89
import jakarta.enterprise.event.Event;
@@ -14,10 +15,10 @@
1415

1516
import com.fasterxml.jackson.core.JsonProcessingException;
1617
import io.a2a.extras.common.events.TaskFinalizedEvent;
18+
import io.a2a.server.config.A2AConfigProvider;
1719
import io.a2a.server.tasks.TaskStateProvider;
1820
import io.a2a.server.tasks.TaskStore;
1921
import io.a2a.spec.Task;
20-
import org.eclipse.microprofile.config.inject.ConfigProperty;
2122
import org.slf4j.Logger;
2223
import org.slf4j.LoggerFactory;
2324

@@ -35,9 +36,24 @@ public class JpaDatabaseTaskStore implements TaskStore, TaskStateProvider {
3536
Event<TaskFinalizedEvent> taskFinalizedEvent;
3637

3738
@Inject
38-
@ConfigProperty(name = "a2a.replication.grace-period-seconds", defaultValue = "15")
39+
A2AConfigProvider configProvider;
40+
41+
/**
42+
* Grace period for task finalization in replicated scenarios (seconds).
43+
* After a task reaches a final state, this is the minimum time to wait before cleanup
44+
* to allow replicated events to arrive and be processed.
45+
* <p>
46+
* Property: {@code a2a.replication.grace-period-seconds}<br>
47+
* Default: 15<br>
48+
* Note: Property override requires a configurable {@link A2AConfigProvider} on the classpath.
49+
*/
3950
long gracePeriodSeconds;
4051

52+
@PostConstruct
53+
void initConfig() {
54+
gracePeriodSeconds = Long.parseLong(configProvider.getValue("a2a.replication.grace-period-seconds"));
55+
}
56+
4157
@Transactional
4258
@Override
4359
public void save(Task task) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# A2A JPA Database Task Store Default Configuration
2+
3+
# Grace period for task finalization in replicated scenarios (seconds)
4+
# After a task reaches a final state, this is the minimum time to wait before cleanup
5+
# to allow replicated events to arrive and be processed
6+
a2a.replication.grace-period-seconds=15
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# A2A Java SDK - MicroProfile Config Integration
2+
3+
This optional integration module provides MicroProfile Config support for the A2A Java SDK configuration system.
4+
5+
## Overview
6+
7+
The A2A Java SDK core uses the `A2AConfigProvider` interface for configuration, with default values loaded from `META-INF/a2a-defaults.properties` files on the classpath.
8+
9+
This module provides `MicroProfileConfigProvider`, which integrates with MicroProfile Config to allow configuration via:
10+
- `application.properties`
11+
- Environment variables
12+
- System properties (`-D` flags)
13+
- Custom ConfigSources
14+
15+
## Quick Start
16+
17+
### 1. Add Dependency
18+
19+
```xml
20+
<dependency>
21+
<groupId>io.github.a2asdk</groupId>
22+
<artifactId>a2a-java-sdk-microprofile-config</artifactId>
23+
<version>${io.a2a.sdk.version}</version>
24+
</dependency>
25+
```
26+
27+
### 2. Configure Properties
28+
29+
Once the dependency is added, you can override any A2A configuration property:
30+
31+
**application.properties:**
32+
```properties
33+
# Executor configuration
34+
a2a.executor.core-pool-size=10
35+
a2a.executor.max-pool-size=100
36+
37+
# Timeout configuration
38+
a2a.blocking.agent.timeout.seconds=60
39+
a2a.blocking.consumption.timeout.seconds=10
40+
```
41+
42+
**Environment variables:**
43+
```bash
44+
export A2A_EXECUTOR_CORE_POOL_SIZE=10
45+
export A2A_BLOCKING_AGENT_TIMEOUT_SECONDS=60
46+
```
47+
48+
**System properties:**
49+
```bash
50+
java -Da2a.executor.core-pool-size=10 -jar your-app.jar
51+
```
52+
53+
## How It Works
54+
55+
The `MicroProfileConfigProvider` implementation:
56+
57+
1. **First tries MicroProfile Config** - Checks `application.properties`, environment variables, system properties, and custom ConfigSources
58+
2. **Falls back to defaults** - If not found, uses values from `META-INF/a2a-defaults.properties` provided by core modules and extras
59+
3. **Priority 50** - Can be overridden by custom providers with higher priority
60+
61+
## Configuration Fallback Chain
62+
63+
```
64+
MicroProfile Config Sources (application.properties, env vars, -D flags)
65+
↓ (not found?)
66+
DefaultValuesConfigProvider
67+
→ Scans classpath for ALL META-INF/a2a-defaults.properties files
68+
→ Merges all discovered properties together
69+
→ Throws exception if duplicate keys found
70+
↓ (property exists?)
71+
Return merged default value
72+
↓ (not found?)
73+
IllegalArgumentException
74+
```
75+
76+
**Note**: All `META-INF/a2a-defaults.properties` files (from server-common, extras modules, etc.) are loaded and merged together by `DefaultValuesConfigProvider` at startup. This is not a sequential fallback chain, but a single merged set of defaults.
77+
78+
## Available Configuration Properties
79+
80+
See the [main README](../../README.md#configuration-system) for a complete list of configuration properties.
81+
82+
## Framework Compatibility
83+
84+
This module works with any MicroProfile Config implementation:
85+
86+
- **Quarkus** - Built-in MicroProfile Config support
87+
- **Helidon** - Built-in MicroProfile Config support
88+
- **Open Liberty** - Built-in MicroProfile Config support
89+
- **WildFly/JBoss EAP** - Add `smallrye-config` dependency
90+
- **Other Jakarta EE servers** - Add MicroProfile Config implementation
91+
92+
## Custom Config Providers
93+
94+
If you're using a different framework (Spring, Micronaut, etc.), you can implement your own `A2AConfigProvider`:
95+
96+
```java
97+
import io.a2a.server.config.A2AConfigProvider;
98+
import io.a2a.server.config.DefaultValuesConfigProvider;
99+
import jakarta.enterprise.context.ApplicationScoped;
100+
import jakarta.enterprise.inject.Alternative;
101+
import jakarta.annotation.Priority;
102+
import jakarta.inject.Inject;
103+
104+
@ApplicationScoped
105+
@Alternative
106+
@Priority(100) // Higher than MicroProfileConfigProvider's priority of 50
107+
public class OtherEnvironmentConfigProvider implements A2AConfigProvider {
108+
109+
@Inject
110+
Environment env;
111+
112+
@Inject
113+
DefaultValuesConfigProvider defaultValues;
114+
115+
@Override
116+
public String getValue(String name) {
117+
String value = env.getProperty(name);
118+
if (value != null) {
119+
return value;
120+
}
121+
// Fallback to defaults
122+
return defaultValues.getValue(name);
123+
}
124+
125+
@Override
126+
public Optional<String> getOptionalValue(String name) {
127+
String value = env.getProperty(name);
128+
if (value != null) {
129+
return Optional.of(value);
130+
}
131+
return defaultValues.getOptionalValue(name);
132+
}
133+
}
134+
```
135+
136+
## Implementation Details
137+
138+
- **Package**: `io.a2a.integrations.microprofile`
139+
- **Class**: `MicroProfileConfigProvider`
140+
- **Priority**: 50 (can be overridden)
141+
- **Scope**: `@ApplicationScoped`
142+
- **Dependencies**: MicroProfile Config API, A2A SDK server-common
143+
144+
## Reference Implementations
145+
146+
The A2A Java SDK reference implementations (Quarkus-based) automatically include this integration module, so MicroProfile Config properties work out of the box.
147+
148+
If you're building a custom server implementation, add this dependency to enable property-based configuration.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?xml version="1.0"?>
2+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<parent>
8+
<groupId>io.github.a2asdk</groupId>
9+
<artifactId>a2a-java-sdk-parent</artifactId>
10+
<version>0.3.3.Beta1-SNAPSHOT</version>
11+
<relativePath>../../pom.xml</relativePath>
12+
</parent>
13+
<artifactId>a2a-java-sdk-microprofile-config</artifactId>
14+
15+
<packaging>jar</packaging>
16+
17+
<name>A2A Java SDK - MicroProfile Config Integration</name>
18+
<description>MicroProfile Config integration for A2A Java SDK - provides A2AConfigProvider implementation</description>
19+
20+
<dependencies>
21+
<dependency>
22+
<groupId>${project.groupId}</groupId>
23+
<artifactId>a2a-java-sdk-server-common</artifactId>
24+
</dependency>
25+
<dependency>
26+
<groupId>jakarta.enterprise</groupId>
27+
<artifactId>jakarta.enterprise.cdi-api</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>jakarta.inject</groupId>
31+
<artifactId>jakarta.inject-api</artifactId>
32+
</dependency>
33+
<dependency>
34+
<groupId>org.eclipse.microprofile.config</groupId>
35+
<artifactId>microprofile-config-api</artifactId>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.slf4j</groupId>
39+
<artifactId>slf4j-api</artifactId>
40+
</dependency>
41+
42+
<!-- Test dependencies -->
43+
<dependency>
44+
<groupId>io.quarkus</groupId>
45+
<artifactId>quarkus-arc</artifactId>
46+
<scope>test</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>io.quarkus</groupId>
50+
<artifactId>quarkus-junit5</artifactId>
51+
<scope>test</scope>
52+
</dependency>
53+
<dependency>
54+
<groupId>org.junit.jupiter</groupId>
55+
<artifactId>junit-jupiter-api</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
</dependencies>
59+
</project>

0 commit comments

Comments
 (0)