jdaugherty opened a new pull request, #16620:
URL: https://github.com/apache/grails-core/pull/16620

   ## Summary
   
   Groovy 6 brings a unified concurrency toolkit into core under [GEP-18: 
Integrated Concurrency and Parallel 
Processing](https://groovy-lang.org/releasenotes/groovy-6.0.html#concurrency-toolkit).
 The `groovy.concurrent` package provides `Awaitable`, `DataflowVariable`, 
`Actor`, `Agent`, `Pool`, `ParallelScope` and the parallel collection methods. 
The release notes describe it as modernising the patterns from GPars around 
virtual threads and structured concurrency, and say previous GPars users "will 
find much of its functionality here". GPars itself (1.2.1, 2014, built against 
Groovy 2.x with a Multiverse dependency we exclude) is a separate, unmaintained 
project, so Grails 9 should stop depending on it.
   
   This PR adds Groovy-native replacements alongside the GPars modules and 
deprecates the GPars modules for removal in a later release.
   
   ## Changes
   
   - **`grails-async-groovy-concurrent`** 
(`org.grails.async.factory.groovy.AwaitablePromiseFactory`, 
`AwaitablePromise`): tasks run through `Awaitable` on Groovy's `async` executor 
(virtual threads by default) or a supplied `Executor`/`Pool`; unfulfilled 
promises are `DataflowVariable`s; every promise is itself an `Awaitable`, so 
`await promise` and `Awaitable.all(p1, p2)` need no conversion. Failure 
semantics follow the default `CompletableFuture` factory (`ExecutionException` 
with the original cause, single `onError` recovers, aggregate `onError` 
observes and stays failed). Promises that are not awaitables are resolved 
inline when done and otherwise bridged on the factory's own executor, so 
bounded pools cannot deadlock on bridging work.
   - **`grails-events-groovy-concurrent`** 
(`org.grails.events.groovy.ActorEventBus`): one reactor actor delivers events 
in publication order off the publishing thread; a subscriber that throws 
without a reply handler is logged and later deliveries continue.
   - **GPars modules deprecated, not removed**: `GparsPromiseFactory`, 
`GparsPromise`, `LoggingPoolFactory` and the GPars `ActorEventBus` carry 
`@Deprecated(since = '9.0', forRemoval = true)` and log a one-time warning 
naming the replacement.
   - **`EventBusFactoryBean`** implements `DisposableBean` and closes a 
`Closeable` bus with the context, so actor-backed buses (Groovy and GPars) do 
not outlive the application.
   - **Internal GPars usage ported**: grails-cache and neo4j tests use 
`everyParallel`/`collectParallel`/`eachParallel` and `ParallelScope.withPool`. 
The two grails-cache cache-manager tests were JUnit 4 classes that the JUnit 
Platform runner never executed; they are now Spock specs that run. The neo4j 
test module drops its GPars dependency. `grails-cache` still declares `api 
gpars` (unused by its main code) and is left as is for now.
   - **Docs**: async and events guide tables list the Groovy modules and mark 
the GPars rows deprecated; the executor configuration advice points at 
`Awaitable.setExecutor`; a new `upgrading90x` page (first Grails 9 upgrade 
page, added to the toc) carries the rationale and migration notes.
   
   Both module sets register through `META-INF/services`, so applications 
switch by replacing the dependency. Only one `PromiseFactory` is service-loaded 
and `EventBusBuilder` refuses more than one `EventBus`, which the docs now 
state.
   
   ## Known limitation
   
   `PromiseFactoryBuilder` ignores Boot's `applicationTaskExecutor` and the 
`TaskDecorator` chain for any service-loaded factory. That is pre-existing 
behaviour shared with the GPars and RxJava factories; the guide now says so and 
names `Awaitable.setExecutor` as the supported knob. Passing the executor 
through the builder is a separate follow-up.
   
   ## Verification
   
   Run locally: specs of both new modules (40 and 10 tests), the GPars module 
specs, grails-events-core and grails-cache suites, `codeStyle` and 
`validateDependencyVersions` for every touched module, 
`validateRepositoryConventions`, and a check that the generated base BOM lists 
the new artifacts. The neo4j `MiscSpec` compiles but needs a Neo4j harness, and 
the guide build and full `aggregateViolations` gate were left to CI.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to