You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/10/13 10:36:38 UTC

(grails-core) branch 9.1.x updated (ab64bb9edb -> 79fa73e0b8)

This is an automated email from the ASF dual-hosted git repository.

jdaugherty pushed a change to branch 9.1.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git


    from ab64bb9edb Merge pull request #16408 from codeconsole/deps/spring-boot-4.2
     add a8535abace Add Groovy 6 groovy.concurrent async and events modules, deprecate GPars
     add 2f777c7799 Remove author tags from files touched by the groovy.concurrent migration
     add 8dc51e090e Merge pull request #16620 from jdaugherty/feat/groovy6-replace-gpars
     add 8237828397 Build with Gradle 9.8.1
     add 093d11297e Merge pull request #16623 from jdaugherty/deps/gradle-9.8.1
     add e57bd1359a fix: preserve configuration snapshots when merging profile metadata
     add 0aa7bf735f fix: support YAML profile expressions and multiple active profiles
     add d6fd8ac1ee fix: handle blank YAML selectors and clarify Groovy profile semantics
     add a643247dd2 fix: evaluate sequence-valued YAML profile selectors
     add b92b61d8df fix: remove selected YAML profile selectors before Boot evaluates them
     add 3ec69de7a2 Merge pull request #16547 from jdaugherty/fix/15840-config-merge-7.0.x
     add c965fc4baa Build with Gradle 8.14.6
     add dd59549883 Merge pull request #16622 from jdaugherty/deps/gradle-8.14.6
     add 84f222b74d Merge branch '7.0.x' into 7.1.x
     add 93bc170840 Merge branch '7.1.x' into 7.2.x
     add b281fe6abf Merge branch '7.2.x' into 8.0.x
     add 9fc21da6b2 Merge branch '8.0.x' into 8.1.x
     add a3f835597a Merge branch '8.1.x' into 9.0.x
     new 79fa73e0b8 Merge branch '9.0.x' into 9.1.x

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .agents/skills/gradle-developer/SKILL.md           |  22 +-
 .github/dependency-graph/external-references.yml   |   2 +
 .sdkmanrc                                          |   2 +-
 build-logic/gradle/wrapper/gradle-wrapper.jar      | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 end-to-end/README.md                               |   2 +-
 end-to-end/gradle/wrapper/gradle-wrapper.jar       | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 end-to-end/legacy-g7-command-plugin/.sdkmanrc      |   4 +-
 .../gradle/wrapper/gradle-wrapper.jar              | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 gradle.properties                                  |   2 +-
 gradle/publish-root-config.gradle                  |   2 +
 gradle/wrapper/gradle-wrapper.jar                  | Bin 47623 -> 48749 bytes
 gradle/wrapper/gradle-wrapper.properties           |   2 +-
 grails-async/README.adoc                           |   2 +-
 .../grails/async/factory/gpars/GparsPromise.groovy |   4 +-
 .../async/factory/gpars/GparsPromiseFactory.groovy |  14 +-
 .../async/factory/gpars/LoggingPoolFactory.groovy  |   3 +-
 .../groovy/grails/async/GparsPromiseSpec.groovy    |  11 +-
 .../{rxjava => groovy-concurrent}/build.gradle     |   4 +-
 .../async/factory/groovy/AwaitablePromise.groovy   | 160 +++++++
 .../factory/groovy/AwaitablePromiseFactory.groovy  | 186 ++++++++
 .../META-INF/services/grails.async.PromiseFactory  |   1 +
 .../groovy/AwaitablePromiseFactorySpec.groovy      | 473 +++++++++++++++++++++
 .../groovy/org/grails/config/NavigableMap.groovy   |  49 ---
 .../groovy/grails/config/NavigableMapSpec.groovy   |  21 +
 .../grails/config/SpringProfileExcludeSpec.groovy  | 173 --------
 ...railsConcurrentLinkedMapCacheManagerSpec.groovy |  97 +++++
 ...ailsConcurrentLinkedMapCacheManagerTests.groovy | 101 -----
 .../GrailsConcurrentMapCacheManagerSpec.groovy     |  97 +++++
 .../GrailsConcurrentMapCacheManagerTests.groovy    | 101 -----
 .../config/yaml/YamlPropertySourceLoader.java      |  66 ++-
 .../grails/boot/GrailsAppYamlProfileSpec.groovy    | 100 +++++
 .../config/PropertySourcesConfigReloadSpec.groovy  | 220 ++++++++++
 .../config/YamlPropertySourceLoaderSpec.groovy     |  23 +
 .../org/grails/config/YamlSpringProfileSpec.groovy | 463 ++++++++++++++++++++
 .../GroovyConfigPropertySourceLoaderSpec.groovy    |  50 +++
 grails-data-neo4j/core/build.gradle                |   1 -
 .../test/groovy/grails/gorm/tests/MiscSpec.groovy  |   8 +-
 grails-doc/src/en/guide/async.adoc                 |   3 +-
 grails-doc/src/en/guide/async/asyncPromises.adoc   |  12 +-
 grails-doc/src/en/guide/async/events.adoc          |  10 +-
 .../src/en/guide/async/events/asyncConfigure.adoc  |   4 +-
 grails-doc/src/en/guide/conf/config.adoc           |  31 ++
 grails-doc/src/en/guide/introduction.adoc          |   2 +-
 .../src/en/guide/upgrading/upgrading90x.adoc       |  25 ++
 .../events/bus/spring/EventBusFactoryBean.groovy   |  15 +-
 .../grails/events/TaskExecuterEventBusSpec.groovy  |  40 ++
 .../org/grails/events/gpars/ActorEventBus.groovy   |  14 +-
 .../grails/events/gpars/ActorEventBusSpec.groovy   |   6 +
 .../{rxjava2 => groovy-concurrent}/build.gradle    |   4 +-
 .../org/grails/events/groovy/ActorEventBus.groovy  | 103 +++++
 .../META-INF/services/grails.events.bus.EventBus   |   1 +
 .../grails/events/groovy/ActorEventBusSpec.groovy  | 215 ++++++++++
 grails-forge/gradle/wrapper/gradle-wrapper.jar     | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../templates/gradleWrapperProperties.rocker.raw   |   2 +-
 grails-gradle/gradle/wrapper/gradle-wrapper.jar    | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../skeleton/gradle/wrapper/gradle-wrapper.jar     | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../skeleton/gradle/wrapper/gradle-wrapper.jar     | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../gradle/wrapper/gradle-wrapper.jar              | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../skills/grails-8-upgrade/SKILL.md               |   2 +-
 .../externalconfig/ExternalConfigSpec.groovy       |  31 ++
 settings.gradle                                    |   4 +
 69 files changed, 2527 insertions(+), 479 deletions(-)
 copy grails-async/{rxjava => groovy-concurrent}/build.gradle (96%)
 create mode 100644 grails-async/groovy-concurrent/src/main/groovy/org/grails/async/factory/groovy/AwaitablePromise.groovy
 create mode 100644 grails-async/groovy-concurrent/src/main/groovy/org/grails/async/factory/groovy/AwaitablePromiseFactory.groovy
 create mode 100644 grails-async/groovy-concurrent/src/main/resources/META-INF/services/grails.async.PromiseFactory
 create mode 100644 grails-async/groovy-concurrent/src/test/groovy/org/grails/async/factory/groovy/AwaitablePromiseFactorySpec.groovy
 delete mode 100644 grails-bootstrap/src/test/groovy/grails/config/SpringProfileExcludeSpec.groovy
 create mode 100644 grails-cache/src/test/groovy/grails/plugin/cache/GrailsConcurrentLinkedMapCacheManagerSpec.groovy
 delete mode 100644 grails-cache/src/test/groovy/grails/plugin/cache/GrailsConcurrentLinkedMapCacheManagerTests.groovy
 create mode 100644 grails-cache/src/test/groovy/grails/plugin/cache/GrailsConcurrentMapCacheManagerSpec.groovy
 delete mode 100644 grails-cache/src/test/groovy/grails/plugin/cache/GrailsConcurrentMapCacheManagerTests.groovy
 create mode 100644 grails-core/src/test/groovy/grails/boot/GrailsAppYamlProfileSpec.groovy
 create mode 100644 grails-core/src/test/groovy/org/grails/config/PropertySourcesConfigReloadSpec.groovy
 create mode 100644 grails-core/src/test/groovy/org/grails/config/YamlSpringProfileSpec.groovy
 copy grails-events/{rxjava2 => groovy-concurrent}/build.gradle (97%)
 create mode 100644 grails-events/groovy-concurrent/src/main/groovy/org/grails/events/groovy/ActorEventBus.groovy
 create mode 100644 grails-events/groovy-concurrent/src/main/resources/META-INF/services/grails.events.bus.EventBus
 create mode 100644 grails-events/groovy-concurrent/src/test/groovy/org/grails/events/groovy/ActorEventBusSpec.groovy


(grails-core) 01/01: Merge branch '9.0.x' into 9.1.x

Posted by jd...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

jdaugherty pushed a commit to branch 9.1.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 79fa73e0b812b934b2f9017d3205b2e61dfef183
Merge: ab64bb9edb a3f835597a
Author: James Daugherty <jd...@jdresources.net>
AuthorDate: Tue Oct 13 11:29:32 2026 +0100

    Merge branch '9.0.x' into 9.1.x

 .agents/skills/gradle-developer/SKILL.md           |  22 +-
 .github/dependency-graph/external-references.yml   |   2 +
 .sdkmanrc                                          |   2 +-
 build-logic/gradle/wrapper/gradle-wrapper.jar      | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 end-to-end/README.md                               |   2 +-
 end-to-end/gradle/wrapper/gradle-wrapper.jar       | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 end-to-end/legacy-g7-command-plugin/.sdkmanrc      |   4 +-
 .../gradle/wrapper/gradle-wrapper.jar              | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 gradle.properties                                  |   2 +-
 gradle/publish-root-config.gradle                  |   2 +
 gradle/wrapper/gradle-wrapper.jar                  | Bin 47623 -> 48749 bytes
 gradle/wrapper/gradle-wrapper.properties           |   2 +-
 grails-async/README.adoc                           |   2 +-
 .../grails/async/factory/gpars/GparsPromise.groovy |   4 +-
 .../async/factory/gpars/GparsPromiseFactory.groovy |  14 +-
 .../async/factory/gpars/LoggingPoolFactory.groovy  |   3 +-
 .../groovy/grails/async/GparsPromiseSpec.groovy    |  11 +-
 grails-async/groovy-concurrent/build.gradle        |  52 +++
 .../async/factory/groovy/AwaitablePromise.groovy   | 160 +++++++
 .../factory/groovy/AwaitablePromiseFactory.groovy  | 186 ++++++++
 .../META-INF/services/grails.async.PromiseFactory  |   1 +
 .../groovy/AwaitablePromiseFactorySpec.groovy      | 473 +++++++++++++++++++++
 .../groovy/org/grails/config/NavigableMap.groovy   |  49 ---
 .../groovy/grails/config/NavigableMapSpec.groovy   |  21 +
 .../grails/config/SpringProfileExcludeSpec.groovy  | 173 --------
 ...railsConcurrentLinkedMapCacheManagerSpec.groovy |  97 +++++
 ...ailsConcurrentLinkedMapCacheManagerTests.groovy | 101 -----
 .../GrailsConcurrentMapCacheManagerSpec.groovy     |  97 +++++
 .../GrailsConcurrentMapCacheManagerTests.groovy    | 101 -----
 .../config/yaml/YamlPropertySourceLoader.java      |  66 ++-
 .../grails/boot/GrailsAppYamlProfileSpec.groovy    | 100 +++++
 .../config/PropertySourcesConfigReloadSpec.groovy  | 220 ++++++++++
 .../config/YamlPropertySourceLoaderSpec.groovy     |  23 +
 .../org/grails/config/YamlSpringProfileSpec.groovy | 463 ++++++++++++++++++++
 .../GroovyConfigPropertySourceLoaderSpec.groovy    |  50 +++
 grails-data-neo4j/core/build.gradle                |   1 -
 .../test/groovy/grails/gorm/tests/MiscSpec.groovy  |   8 +-
 grails-doc/src/en/guide/async.adoc                 |   3 +-
 grails-doc/src/en/guide/async/asyncPromises.adoc   |  12 +-
 grails-doc/src/en/guide/async/events.adoc          |  10 +-
 .../src/en/guide/async/events/asyncConfigure.adoc  |   4 +-
 grails-doc/src/en/guide/conf/config.adoc           |  31 ++
 grails-doc/src/en/guide/introduction.adoc          |   2 +-
 .../src/en/guide/upgrading/upgrading90x.adoc       |  25 ++
 .../events/bus/spring/EventBusFactoryBean.groovy   |  15 +-
 .../grails/events/TaskExecuterEventBusSpec.groovy  |  40 ++
 .../org/grails/events/gpars/ActorEventBus.groovy   |  14 +-
 .../grails/events/gpars/ActorEventBusSpec.groovy   |   6 +
 grails-events/groovy-concurrent/build.gradle       |  53 +++
 .../org/grails/events/groovy/ActorEventBus.groovy  | 103 +++++
 .../META-INF/services/grails.events.bus.EventBus   |   1 +
 .../grails/events/groovy/ActorEventBusSpec.groovy  | 215 ++++++++++
 grails-forge/gradle/wrapper/gradle-wrapper.jar     | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../templates/gradleWrapperProperties.rocker.raw   |   2 +-
 grails-gradle/gradle/wrapper/gradle-wrapper.jar    | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../skeleton/gradle/wrapper/gradle-wrapper.jar     | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../skeleton/gradle/wrapper/gradle-wrapper.jar     | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../gradle/wrapper/gradle-wrapper.jar              | Bin 47623 -> 48749 bytes
 .../gradle/wrapper/gradle-wrapper.properties       |   2 +-
 .../skills/grails-8-upgrade/SKILL.md               |   2 +-
 .../externalconfig/ExternalConfigSpec.groovy       |  31 ++
 settings.gradle                                    |   4 +
 69 files changed, 2630 insertions(+), 473 deletions(-)

diff --cc grails-doc/src/en/guide/upgrading/upgrading90x.adoc
index e690f8ff2f,c40de2e35c..4566fe6431
--- a/grails-doc/src/en/guide/upgrading/upgrading90x.adoc
+++ b/grails-doc/src/en/guide/upgrading/upgrading90x.adoc
@@@ -17,104 -17,32 +17,129 @@@ specific language governing permission
  under the License.
  ////
  
 -=== Upgrade Instructions for Grails and Related Dependencies
 +=== Upgrade Instructions for Grails 8 to Grails 9
  
 -To ensure compatibility with Grails {version}, please review the following upgrade instructions carefully.
 -This guide outlines the necessary steps and warnings to upgrade your Grails project from Grails 8.x to Grails 9.
 +This guide outlines the changes introduced in Grails 9 and the steps required to upgrade your application.
  
 -==== 1. GPars Integration Deprecated in Favour of Groovy Concurrency
 +==== 1. Spring Boot 4.2 and Spring Framework 7.1
 +
 +Grails 9 moves from Spring Boot 4.1 and Spring Framework 7.0, which Grails 8 uses, to Spring Boot {springBootVersion} and Spring Framework {springVersion}.
 +The managed versions that change include Spring Security 7.2, Spring Data 2026.1, Micrometer 1.18 and Reactor 2026.0.
 +Review the https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-4.2-Release-Notes[Spring Boot 4.2 Release Notes] and the https://github.com/spring-projects/spring-framework/wiki/Spring-Framework-7.1-Release-Notes[Spring Framework 7.1 Release Notes] for the changes that affect your application.
 +The ones most likely to affect a Grails application are:
 +
 +* *`server.forward-headers-strategy: framework` reads only the `+X-Forwarded-*+` headers by default.*
 +Spring Framework 7.1's `ForwardedHeaderFilter` reads either the RFC 7239 `Forwarded` header or the `+X-Forwarded-*+` headers, and Spring Boot 4.2 configures it for `+X-Forwarded-*+`.
 +Before, it read `Forwarded` when the request carried one and `+X-Forwarded-*+` otherwise.
 +If your reverse proxy sends `Forwarded`, set `spring.mvc.forwarded-headers.header-format: standard`.
 +Spring Boot 4.2 also registers the filter from its Spring MVC auto-configuration, which backs off when the application declares `@EnableWebMvc`; such an application must now register a `ForwardedHeaderFilter` itself.
 +
 +* *Embedded Tomcat keeps relative redirect locations relative.*
 +`server.tomcat.servlet.use-relative-redirects`, renamed from `server.tomcat.use-relative-redirects`, now defaults to `true`, Tomcat's own default.
 +A redirect sent through `HttpServletResponse.sendRedirect` with a path, such as a controller `chain` call, a Spring Security redirect or a `redirect:` view name, now has a relative `Location` header instead of an absolute URL.
 +A controller `redirect` sets the `Location` header itself and still sends an absolute URL unless you pass `absolute: false`.
 +Browsers resolve relative locations; set the property to `false` if a client or test expects an absolute URL.
 +
 +* *`TestRestTemplate` is deprecated for removal.*
 +Spring Framework 7.1 deprecates `RestTemplate`, and Spring Boot 4.2 deprecates `TestRestTemplate` and `@AutoConfigureTestRestTemplate` with it.
 +Move `@SpringBootTest` tests to `RestTestClient`, which `@AutoConfigureRestTestClient` injects:
 ++
 +[source,groovy]
 +----
 +// Before
 +import org.springframework.boot.resttestclient.TestRestTemplate
 +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate
 +
 +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 +@AutoConfigureTestRestTemplate
 +class BookApiSpec extends Specification {
 +    @Autowired TestRestTemplate rest
 +}
 +
 +// After
 +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureRestTestClient
 +import org.springframework.test.web.servlet.client.RestTestClient
 +
 +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
 +@AutoConfigureRestTestClient
 +class BookApiSpec extends Specification {
 +    @Autowired RestTestClient client
 +}
 +----
 +
 +* *Spring MVC no longer detects the JAXB XML converter.*
 +Spring Framework 7.1 stops auto-detecting the JAXB message converter for server applications.
 +Grails `render` and `respond` write XML through Grails' own converters and are unaffected.
 +A Spring MVC `@RestController` that returns JAXB-annotated objects needs the converter registered explicitly, as the Spring Framework 7.1 release notes show.
 +
 +* *Tests load static nested `@Configuration` classes from their superclasses and enclosing classes.*
 +The Spring TestContext Framework used to ignore such a class unless its class hierarchy declared `@ContextConfiguration`, and now adds it to the test's application context.
 +Grails 8 already logs a warning for each one it ignores, so a test run on Grails 8 shows the affected tests.
 +Remove the `@Configuration` annotation, or move the class to a top-level class, if the test should not load it.
 +
 +==== 2. graphql-java 26 for GraphQL Applications
 +
 +Spring Boot 4.2 manages graphql-java 26, so applications using the GraphQL plugin (`grails-data-graphql`) move from graphql-java 25 to graphql-java 26.1.
 +graphql-java 26.0 contains breaking changes, listed in its https://github.com/graphql-java/graphql-java/releases/tag/v26.0[release notes].
 +The ones that can affect a Grails application are:
 +
 +* *Query complexity limits are enforced by default.*
 +A query nested more than 100 levels deep, or selecting more than 100,000 fields, now fails validation with a `MaxQueryDepthExceeded` or `MaxQueryFieldsExceeded` error.
 +To raise the limits, or to turn them off, set new defaults when the application starts, for example in `BootStrap.groovy`:
 ++
 +[source,groovy]
 +----
 +import graphql.validation.QueryComplexityLimits
 +
 +class BootStrap {
 +
 +    def init = {
 +        QueryComplexityLimits.setDefaultLimits(QueryComplexityLimits.newLimits()
 +                .maxDepth(150)
 +                .maxFieldsCount(200_000)
 +                .build())
 +        // or, to turn the limits off:
 +        // QueryComplexityLimits.setDefaultLimits(QueryComplexityLimits.NONE)
 +    }
 +}
 +----
 ++
 +graphql-java's parser separately rejects a query nested more than about 165 levels deep, so a `maxDepth` above that has no effect.
 +
 +* *Schemas built in code are validated like schemas built from SDL.*
 +A required argument or input field (non-null with no default value) can no longer be deprecated.
 +The schema the plugin generates never deprecates an argument or an input field, but arguments and input types an application adds through a `GraphQLSchemaInterceptor` must follow the rule.
 +
 +* *Additional schema types must be named types.*
 +`GraphQLSchemaInterceptor.interceptSchema` still receives the additional types as a `Set<GraphQLType>`, and the plugin unwraps list and non-null wrappers before it builds the schema, so existing interceptors need no change.
 +Code that builds a `GraphQLSchema` directly must pass `GraphQLNamedType` instances to `GraphQLSchema.Builder.additionalTypes`.
 +
 +The other breaking changes (the validation rule filter, the removal of `DirectiveInfo`, and the JSpecify nullability annotations) only affect code that uses graphql-java directly.
 +The nullability annotations document existing behavior and do not change what graphql-java returns at runtime.
 +
 +The plugin continues to use graphql-java-extended-scalars 24.0, its latest release, which works with graphql-java 26.1.
++
++==== 3. GPars Integration Deprecated in Favour of Groovy Concurrency
+ 
+ Grails 9 builds on Groovy 6, which brings a unified concurrency and parallel-processing toolkit into core under https://groovy-lang.org/releasenotes/groovy-6.0.html#concurrency-toolkit[GEP-18: Integrated Concurrency and Parallel Processing]. The `groovy.concurrent` package provides `Awaitable`, `DataflowVariable`, `Actor`, `Agent`, `Pool`, `ParallelScope` and the parallel collection methods such as `eachParallel` and `collectParallel`. The Groovy release notes describe the toolkit as mo [...]
+ 
+ With those patterns part of the language, Grails no longer needs the separate GPars library, which was last released in 2014 and depends on Groovy 2.x and the Multiverse STM engine. The `grails-async-gpars` and `grails-events-gpars` modules remain available in Grails 9 but are deprecated for removal: their classes carry `@Deprecated(since = '9.0', forRemoval = true)` and log a warning when selected. They will be removed in a future release.
+ 
+ Their replacements are `grails-async-groovy-concurrent`, providing `org.grails.async.factory.groovy.AwaitablePromiseFactory`, and `grails-events-groovy-concurrent`, providing `org.grails.events.groovy.ActorEventBus`. Both are selected the same way the GPars modules are, by adding the dependency in place of the GPars one:
+ 
+ [source,groovy]
+ .build.gradle
+ ----
+ runtimeOnly 'org.apache.grails.async:grails-async-groovy-concurrent'
+ runtimeOnly 'org.apache.grails.events:grails-events-groovy-concurrent'
+ ----
+ 
+ Do not keep both the GPars and the Groovy module on the classpath: only the first service-loaded `PromiseFactory` is used, and the event bus builder refuses to start when more than one `EventBus` implementation is found.
+ 
+ The Groovy promise factory follows the failure contract of the default `CompletableFuture` factory rather than the GPars one: direct and chained `get()` calls throw `ExecutionException` with the original failure as the cause, a single-promise `onError` recovers with its callback result, and the aggregate `onError` observes the failure and leaves the returned promise failed. `onComplete` and `then` return a new promise instead of the receiver. Promises created by this factory are also Gr [...]
+ 
+ The Groovy actor event bus delivers each event to its subscribers in publication order on a single Groovy actor. A subscriber that throws without a reply handler is logged and does not stop delivery to the remaining subscribers or later events.
+ 
+ Applications that use GPars directly, for example `GParsPool.withPool { list.eachParallel { } }`, should move to the Groovy equivalents: the parallel collection methods are available on every `Collection` without a pool, and `groovy.concurrent.ParallelScope.withPool(n) { scope -> list.eachParallel { } }` runs them on a pool of a chosen size. Once the deprecated modules are removed, Grails will no longer bring GPars onto the classpath, so an application that still needs it must declare ` [...]
+ 
+ NOTE: Groovy 6 marks the concurrency toolkit as incubating. The Grails modules that build on it expose only the Grails `Promise` and `EventBus` contracts, so changes to the Groovy API in later Groovy releases are absorbed by Grails rather than by application code.