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]
