Redouble AI Nucleo documentation
Part 7 · Hundreds of agents in one JVM

Connections from a DataSource

ai.redouble.nucleo.jdbc · nucleo-core

For an application whose database access is a plain javax.sql.DataSource, this package gives a tool a java.sql.Connection of its own for exactly as long as the tool runs. The connection is checked out of the application's pool when the job is admitted, stays with the job through every statement and transaction, and goes back to the pool when the job ends, whether it succeeded, failed or timed out. The tool never opens or closes it.

JdbcResourceProvider is a database provider in the sense of Admission: the application registers it once under a name with a limit, and admission lets at most that many jobs hold one of its connections at a time. The Hibernate provider is in nucleo-hibernate (Hibernate sessions), and the Spring provider in the Spring Boot starter.

Registering the provider

The application registers the provider once at startup, before any job uses it, with the name jobs will look it up by, its DataSource, and how many jobs may hold a connection at once:

JdbcResourceProvider db = new JdbcResourceProvider("default", dataSource, 20);
DBResourceProviders.register(db);

The pool behind the DataSource stays the application's: Hikari, Agroal, DBCP, UCP or a container's JNDI pool. The provider never reads, sizes or tunes it. The limit is yours to state, and it must not exceed the connections the pool can spare for jobs. When other code shares the pool, such as web requests or a scheduler, and has used up every connection, a job that was admitted waits inside the pool for as long as the pool's own checkout timeout allows; a checkout that fails fails the job, and no retry can help it. The limit shows up in the health snapshot as db:<name>.

Using it in a tool

The tool looks the provider up by name, declares it, and takes its connection in execute:

// in a job
JdbcResourceProvider db = DBResourceProviders.get("default", JdbcResourceProvider.class);
req.addProvider(db);
req.setRequiresTransaction(true);
...
Connection connection = resources.get(db);

With setRequiresTransaction(true) Nucleo begins a transaction before execute, commits it after, and rolls it back when execute throws. Without it the connection is in auto-commit, and the tool can run transactions of its own on it: begin turns auto-commit off, and commit and rollback end the transaction and turn it back on, so one job can run several transactions on its one connection. A job that declares setReadOnly(true) gets a connection marked read-only.

The connection belongs to the provider: the tool must not close it, and Nucleo returns it at the end.

What happens at the end

Closing or aborting twice does nothing the second time, a rollback with no transaction open or after an abort does nothing, and a handle made by another provider is refused with IllegalArgumentException. JdbcResourceProviderTest holds each of these rules, together with the contract every provider passes (DBResourceProviderContract in nucleo-core's test-jar).

^