Redouble AI Nucleo documentation
Part 13 · Inside the runtime

Inside the Spring Boot starter

ai.redouble.nucleo.spring · nucleo-spring-boot-starter

This page is for people working on the runtime itself. How to run Nucleo in a Spring Boot application is in Spring Boot.

What is here

TypeRole
SpringSecretsThe runtime's credential store: nucleo.credentials.<id> answers the secret, .user and .host the other parts. A bean, so Spring's Environment reaches it; the runtime builds its instances by reflection and they read the same environment.
SpringEnvironmentThe NucleoConfigurator the starter registers under META-INF/services: it assigns SpringSecrets as the store and leaves every other default alone.
SpringSettingsBinderMaps nucleo.* application properties onto the registered Settings classes: nucleo.http.pool-size binds HttpSettings.poolSize - the class minus Settings and the field, both kebab-cased. Runs before any bean builds; a bound property overwrites what the configurator set.
NucleoRuntimeA SmartLifecycle bean at phase 0, below the web server's: starts the dispatcher, subscribes the event log and the CostLedger, registers the ledger as the spend gate, and drains the dispatcher on stop - only a dispatcher it started itself, since the dispatcher is process-wide. Stays down in discover mode.
NucleoSpringApplicationrun(Application.class, args) in place of SpringApplication.run: discover as the first argument runs CatalogDiscovery in a context without the web server and exits with its code.
NucleoAutoConfigurationDeclares the beans - the store, the runtime and the database registration each @ConditionalOnMissingBean, so a host that declares its own replaces them, plus the settings binder.
NucleoDatabaseCalls DBResourceProviders.registerDefault() once every bean exists, registering the core CountingDBResourceProvider from nucleo.database.* when max-concurrent is set; unregisters it when the context closes.
SpringTransactionResourceProviderOpt-in: the DBResourceProvider over a Spring ResourceTransactionManager that holds one connection per job from admission to its end, so a job's repositories, JdbcTemplate and @Transactional services run on the connection it was admitted for. A host registers it itself.
HeldConnection, HeldEntityManagerWhat the provider holds and binds to a job's thread: a connection under a datasource manager, a Hibernate session under a JPA manager.

How the held connection is bound

At admission the provider checks the connection out and binds it to the job's thread the way Spring's open-in-view support binds a request's: a ConnectionHolder under a DataSourceTransactionManager, an EntityManagerHolder over a Hibernate session held in DELAYED_ACQUISITION_AND_HOLD under a JpaTransactionManager, with the session's connection bound for the manager's datasource between transactions so plain JDBC beside JPA stays on it. Every transaction the job runs, and every data access outside one, lands on that connection, except a transaction that suspends the one under way (REQUIRES_NEW): Spring runs it on a second connection from the pool, outside the admission bound, and hands it back when it ends. A JPA provider other than Hibernate, and any other kind of resource, is refused when the provider is built. Spring binds transactions to a thread: begin, commit and rollback run on the job's thread and refuse any other; a close on another thread - the dispatcher's timeout enforcement - returns the connection directly, and the job thread's bindings die with it. awaitCompletion returns at once, since the manager's commit is a JDBC commit the server acknowledged. SpringTransactionResourceProviderTest and SpringJpaTransactionResourceProviderTest hold these rules beside the provider contract.

Discover mode and the runtime

NucleoRuntime stays down for discover mode, because the discovery seals its own permitting envelope to ask what the account can call and a started dispatcher would have sealed the refusing default first.

Tests

SpringSecretsTest pins the credential store: the three parts from their three properties, a part no property binds read from its environment variable while a bound part wins, a declared shape deciding what is read and asked for, and a store asked before the context exists refusing. NucleoDatabaseTest holds the database registration. NucleoAutoConfigurationTest pins the beans the starter declares, the binding of nucleo.* properties, printAllListsSettingsContributedByOtherJars, a host's own runtime bean replacing the starter's, and a context that did not start the dispatcher leaving it running when it closes.

^