Skip to content

Commit a631ff1

Browse files
feat: Add DatabaseSessionService with JDBC and Flyway support
Summary Implements a production-ready database-backed session service that provides persistent storage for ADK sessions, events, and state using JDBC. Key Features - JDBC with HikariCP connection pooling for optimal performance - Flyway migrations for schema versioning and zero-downtime deployments - Multi-database support: PostgreSQL, MySQL, H2, Cloud Spanner, and other RDBMS - Thread-safe operations with pessimistic locking for concurrent updates - Comprehensive test coverage with H2 in-memory database - Dialect-aware JSON storage (JSONB for PostgreSQL, CLOB for others) - Event filtering and pagination for efficient data retrieval Architecture - Located in contrib/database-session-service module - Minimal core dependencies footprint - Users explicitly opt-in via dependency - Follows existing contrib pattern
1 parent b66e4a5 commit a631ff1

48 files changed

Lines changed: 9689 additions & 1 deletion

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Database Session Service
2+
3+
A pure JDBC-based session service implementation for ADK Java with **zero external persistence dependencies**.
4+
5+
## Features
6+
7+
- **Zero ORM Dependencies**: Uses pure JDBC with HikariCP for connection pooling
8+
- **Multi-Database Support**: PostgreSQL, MySQL, H2 (SQLite not supported)
9+
- **Automatic Schema Management**: Flyway migrations handle table creation/updates
10+
- **3-Tier State Storage**: Separate tables for app-level, user-level, and session-level state
11+
- **Reactive API**: RxJava 3 Single/Maybe/Completable return types
12+
13+
## Dependencies
14+
15+
- **HikariCP**: High-performance JDBC connection pool
16+
- **Flyway**: Database schema versioning and migration
17+
- **Jackson**: JSON serialization for events and state
18+
- **RxJava 3**: Reactive programming support
19+
20+
## Database Schema
21+
22+
The service creates and manages these tables:
23+
24+
- `app_states`: Application-level state (shared across all users)
25+
- `user_states`: User-level state (shared across user's sessions)
26+
- `sessions`: Individual session data
27+
- `events`: Event history for each session
28+
29+
## Usage
30+
31+
```java
32+
// Create service with database URL
33+
String dbUrl = "jdbc:postgresql://localhost:5432/adk?user=postgres&password=secret";
34+
try (DatabaseSessionService sessionService = new DatabaseSessionService(dbUrl)) {
35+
36+
// Create a session
37+
Session session = sessionService.createSession(
38+
"myApp",
39+
"user123",
40+
new ConcurrentHashMap<>(),
41+
null
42+
).blockingGet();
43+
44+
// Append an event
45+
Event event = Event.builder()
46+
.id(UUID.randomUUID().toString())
47+
.invocationId("inv-1")
48+
.timestamp(System.currentTimeMillis())
49+
.build();
50+
51+
Event appendedEvent = sessionService.appendEvent(session, event).blockingGet();
52+
}
53+
```
54+
55+
## Supported Databases
56+
57+
- **PostgreSQL**: Full support with JSONB
58+
- URL: `jdbc:postgresql://host:port/database?user=...&password=...`
59+
- **MySQL**: Full support with JSON
60+
- URL: `jdbc:mysql://host:port/database?user=...&password=...`
61+
- **H2**: For testing and development
62+
- URL: `jdbc:h2:mem:testdb` or `jdbc:h2:file:./data/mydb`
63+
- **Cloud Spanner**: Full support
64+
- URL: `jdbc:cloudspanner:/projects/PROJECT_ID/instances/INSTANCE_ID/databases/DATABASE_ID`
65+
- **SQLite**: NOT supported (no UPSERT support)
66+
67+
## State Management
68+
69+
State is stored across three tables with merge priority:
70+
71+
1. **App State** (lowest priority): `app:key` prefix
72+
2. **User State** (medium priority): `user:key` prefix
73+
3. **Session State** (highest priority): No prefix
74+
75+
When retrieving a session, states are merged: app → user → session (higher priority overwrites).
76+
77+
## Configuration
78+
79+
Optional properties can be passed to the constructor:
80+
81+
```java
82+
Map<String, Object> props = new HashMap<>();
83+
props.put("connectionTimeout", 30000);
84+
props.put("maximumPoolSize", 10);
85+
86+
DatabaseSessionService service = new DatabaseSessionService(dbUrl, props);
87+
```
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright 2025 Google LLC
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0"
18+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<modelVersion>4.0.0</modelVersion>
21+
22+
<parent>
23+
<groupId>com.google.adk</groupId>
24+
<artifactId>google-adk-parent</artifactId>
25+
<version>0.5.1-SNAPSHOT</version>
26+
<relativePath>../../pom.xml</relativePath>
27+
</parent>
28+
29+
<artifactId>google-adk-database-session-service</artifactId>
30+
<name>Agent Development Kit - Database Session Service</name>
31+
<description>Pure JDBC session management for ADK - zero external persistence dependencies, Google-style minimal utilities</description>
32+
33+
<dependencies>
34+
<!-- ADK Core (required) -->
35+
<dependency>
36+
<groupId>com.google.adk</groupId>
37+
<artifactId>google-adk</artifactId>
38+
<version>${project.version}</version>
39+
</dependency>
40+
41+
<!-- ZERO external persistence libraries - just standard JDBC from JDK -->
42+
<!-- This demonstrates Google's philosophy: minimize dependencies, use standard library -->
43+
44+
<!-- HikariCP - High-performance JDBC connection pool -->
45+
<dependency>
46+
<groupId>com.zaxxer</groupId>
47+
<artifactId>HikariCP</artifactId>
48+
</dependency>
49+
50+
<!-- Jackson for JSON serialization (minimal, standard library) -->
51+
<dependency>
52+
<groupId>com.fasterxml.jackson.core</groupId>
53+
<artifactId>jackson-databind</artifactId>
54+
</dependency>
55+
56+
<!-- RxJava for reactive API (required by BaseSessionService) -->
57+
<dependency>
58+
<groupId>io.reactivex.rxjava3</groupId>
59+
<artifactId>rxjava</artifactId>
60+
</dependency>
61+
62+
<!-- SLF4J API for logging -->
63+
<dependency>
64+
<groupId>org.slf4j</groupId>
65+
<artifactId>slf4j-api</artifactId>
66+
</dependency>
67+
68+
<!-- Database Migration -->
69+
70+
<!-- Flyway Core - Database schema migration and versioning tool -->
71+
<dependency>
72+
<groupId>org.flywaydb</groupId>
73+
<artifactId>flyway-core</artifactId>
74+
</dependency>
75+
76+
<!-- Flyway PostgreSQL Support -->
77+
<dependency>
78+
<groupId>org.flywaydb</groupId>
79+
<artifactId>flyway-database-postgresql</artifactId>
80+
<scope>runtime</scope>
81+
</dependency>
82+
83+
<!-- Flyway MySQL Support -->
84+
<dependency>
85+
<groupId>org.flywaydb</groupId>
86+
<artifactId>flyway-mysql</artifactId>
87+
<scope>runtime</scope>
88+
</dependency>
89+
90+
<!-- Flyway Spanner Support -->
91+
<dependency>
92+
<groupId>org.flywaydb</groupId>
93+
<artifactId>flyway-gcp-spanner</artifactId>
94+
<scope>runtime</scope>
95+
</dependency>
96+
97+
<!-- Database Drivers (optional - users choose their own) -->
98+
99+
<!-- PostgreSQL Driver -->
100+
<dependency>
101+
<groupId>org.postgresql</groupId>
102+
<artifactId>postgresql</artifactId>
103+
<optional>true</optional>
104+
</dependency>
105+
106+
<!-- MySQL Driver -->
107+
<dependency>
108+
<groupId>com.mysql</groupId>
109+
<artifactId>mysql-connector-j</artifactId>
110+
<optional>true</optional>
111+
</dependency>
112+
113+
<!-- Spanner JDBC Driver -->
114+
<dependency>
115+
<groupId>com.google.cloud</groupId>
116+
<artifactId>google-cloud-spanner-jdbc</artifactId>
117+
<optional>true</optional>
118+
</dependency>
119+
120+
<!-- Test Dependencies -->
121+
122+
<!-- H2 Database - In-memory database for testing -->
123+
<dependency>
124+
<groupId>com.h2database</groupId>
125+
<artifactId>h2</artifactId>
126+
<scope>test</scope>
127+
</dependency>
128+
129+
<dependency>
130+
<groupId>org.junit.jupiter</groupId>
131+
<artifactId>junit-jupiter-api</artifactId>
132+
<scope>test</scope>
133+
</dependency>
134+
135+
<dependency>
136+
<groupId>org.junit.jupiter</groupId>
137+
<artifactId>junit-jupiter-params</artifactId>
138+
<scope>test</scope>
139+
</dependency>
140+
141+
<dependency>
142+
<groupId>org.junit.jupiter</groupId>
143+
<artifactId>junit-jupiter-engine</artifactId>
144+
<scope>test</scope>
145+
</dependency>
146+
147+
<dependency>
148+
<groupId>org.slf4j</groupId>
149+
<artifactId>slf4j-simple</artifactId>
150+
<scope>test</scope>
151+
</dependency>
152+
153+
<dependency>
154+
<groupId>com.google.truth</groupId>
155+
<artifactId>truth</artifactId>
156+
<scope>test</scope>
157+
</dependency>
158+
159+
<dependency>
160+
<groupId>org.mockito</groupId>
161+
<artifactId>mockito-core</artifactId>
162+
<scope>test</scope>
163+
</dependency>
164+
</dependencies>
165+
166+
<build>
167+
<resources>
168+
<resource>
169+
<directory>src/main/resources</directory>
170+
<filtering>true</filtering>
171+
</resource>
172+
</resources>
173+
<plugins>
174+
<plugin>
175+
<artifactId>maven-compiler-plugin</artifactId>
176+
</plugin>
177+
<plugin>
178+
<groupId>org.jacoco</groupId>
179+
<artifactId>jacoco-maven-plugin</artifactId>
180+
</plugin>
181+
<plugin>
182+
<groupId>org.apache.maven.plugins</groupId>
183+
<artifactId>maven-surefire-plugin</artifactId>
184+
</plugin>
185+
</plugins>
186+
</build>
187+
</project>

0 commit comments

Comments
 (0)