To make sure that we trigger transactional event listeners from Scenario based integration tests, we trigger stimulus executions using transactions configured to require a new transaction. This makes sure that Scenarios work in integration tests using @Transactional, of course circumventing the default rollback behavior of those transactions. There's no other way to implement this as we *need* to commit a transaction to trigger the delivery of transaction-bound events.
Fixed a bug in the handling of Scenario.stimulus(Supplier<T>) as for this, the Supplier handed into the method had not been executed transactionally at all.
We now tweak the task executor to await termination for 2 seconds unless explicitly disabled or any of the Spring Boot task executor shutdown properties being set. This makes sure that long running application module listeners do not access resources already in shutdown when running integration tests, in which the context could already shutdown while the listener is still running.
We now use an AsyncTaskExecutor to bootstrap the ApplicationModules instance at startup asynchronously and - at the same time - do not block an explicit application shutdown. This also more idiomatic compared to using an ExecutorService directly.
Move the registration of cleanup callbacks to the intermediate When type to avoid overloads of Scenario.stimulate(…). Also, to prevent multiple lambda-style parameters for ….stimulate(…) as they don't distinguish nice on the declaration side. Removed the varargs from ….publish(…) methods and wait for the actual request to add support for preparing, in transaction callbacks (potentially to be introduced as ….prepare(…) method).
The default acceptance criteria for state change expectations now also considers a boolean true as concluding method result.
Set up dedicated GitHub actions workflow to run tests against upcoming Spring Boot snapshots and milestones. Introduced with-preview-repos build profile to activate the Maven repositories containing snapshots and milestones.
We now ship a spring-modulith-starter-core that includes dependencies that will typically be used for core runtime support, including the spring-modulith-moments and …-api artifacts in compile scope (so that production code can refer to them) as well as both the …-core and …-runtime artifacts in runtime scope (primarily for ApplicationModuleListener support).
The persistence-technology-specific event publication registry starters now refer to that core starter.
Introduced ApplicationModulesExporter to render an ApplicationModules instances as JSON directly. To avoid a dependency to a JSON library and as we only have to be able to render rather simple arrangements, we just build up the JSON string ourselves.
ApplicationModulesEndpoint now caches the structure calculated once to avoid repeated work.
Previously we used a dedicated BeanPostProcessor to decorate beans that expose transactional event listeners with an interceptor to mark event publications as completed if the method invocation completes successfully. We now have simplified the arrangement by using Spring's auto-proxy creation and registering an Advisor implementation. This allows us to properly and reliably order the interceptor between the async one (goes before ours) and the transactional one (goes after ours). Also, this significantly simplifies the implementation of the interceptor as we can assume only commit listener methods being intercepted in the first place.
The ApplicationListener we deploy to capture events published during a test method execution now uses an InheritableThreadLocal so that events published on threads spawned from the main test execution thread also end up in the PublishedEvents instance prepared for the test method.
Also, the registration of that particular event listener avoids duplicate registrations by inspecting the application context in use for the test method execution for an already registered listener, falling back to registering one.