Add VirtualThreadPromiseFactory seed - #15960
Conversation
Introduce virtual-thread PromiseFactory and document GPars deprecation path. Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]
There was a problem hiding this comment.
Pull request overview
This PR seeds Java 21 virtual-thread support in grails-async by introducing a new VirtualThreadPromiseFactory, wiring it into PromiseFactoryBuilder behind an opt-in system property, and documenting the intended deprecation direction for GPars.
Changes:
- Added
VirtualThreadPromiseFactory(virtual-thread-per-task executor) tograils-async-core. - Updated
PromiseFactoryBuilderto select the virtual-thread factory when-Dgrails.async.promiseFactory=virtual-threadis set and noServiceLoaderfactory is present. - Updated async guide documentation and added a new Spock spec covering selection/execution.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
grails-async/core/src/main/groovy/org/grails/async/factory/future/VirtualThreadPromiseFactory.groovy |
Adds the new virtual-thread-backed PromiseFactory implementation. |
grails-async/core/src/main/groovy/org/grails/async/factory/PromiseFactoryBuilder.groovy |
Adds opt-in selection for the virtual-thread factory via system property. |
grails-async/core/src/test/groovy/grails/async/VirtualThreadPromiseFactorySpec.groovy |
Adds tests for opt-in selection and basic execution behavior. |
grails-doc/src/en/guide/async/asyncPromises.adoc |
Documents the opt-in virtual-thread factory and notes GPars deprecation direction. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
We've previously discussed with @paulk-asert about integrating Gpars into groovy. I do not agree with it's deprecation. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## 8.0.x #15960 +/- ##
==================================================
+ Coverage 49.5403% 51.4992% +1.9589%
- Complexity 16922 17788 +866
==================================================
Files 1999 2040 +41
Lines 93754 95617 +1863
Branches 16420 16593 +173
==================================================
+ Hits 46446 49242 +2796
+ Misses 40145 39061 -1084
- Partials 7163 7314 +151
🚀 New features to boost your workflow:
|
|
Thanks for the context on the GPars-into-Groovy discussions with @paulk-asert. To separate the two things this PR touches: the deprecation of GPars and the modern virtual-thread path are independent decisions, and I'd propose decoupling them here.
I'll rescope the PR to "add the VirtualThreadPromiseFactory seed" with GPars left as-is. Does that address the concern? |
jdaugherty
left a comment
There was a problem hiding this comment.
Other than the Gpars reference still, I'm ok with this PR
…on language Addresses all 6 unresolved review comments (5 from Copilot, 1 from jdaugherty), each verified before fixing: - onComplete/onError constructed their FutureTaskPromise by casting the submitted closure to Closure<List<T>>, but the closure's actual returned value was callable.call(values) - typed T, not List<T>. Reproduced the resulting failure standalone outside the module first: a caller consuming the result as a statically-typed List<T> (the declared contract of Promise<List<T>>) hits a real GroovyCastException/ClassCastException at runtime, not just a theoretical mismatch. Fixed by resolving the promise to the actual waited-on List<T> (invoking the callback purely for its side effect, matching what "completion callback" implies) rather than the callback's own T-typed return value; onError now resolves to an empty list on failure instead of the same List<T>-typed lie. Added tests for onComplete/onError that consume the result as a statically-typed List to lock the fix in - these methods previously had zero test coverage. - close() is now idempotent (guards on isShutdown()), matching CachedThreadPoolPromiseFactory's sibling implementation. - @SInCE tags/doc version references corrected from 8.1 to 8.0, the actual branch/version this ships on. - Test spec snapshots and restores the grails.async.promiseFactory system property and Promises.promiseFactory static field instead of unconditionally clearing them (parallel-fork test isolation), and closes the factory PromiseFactoryBuilder.build() constructs instead of leaking its ExecutorService. - Removed the "GPars support is prepared for deprecation" doc language per jdaugherty's explicit objection (an active GPars/Groovy integration discussion is in progress with paulk-asert) and jamesfredley's agreed rescope: the virtual-thread factory is additive and opt-in, so it doesn't need to say anything about GPars' lifecycle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
✅ All tests passed ✅🏷️ Commit: 3cd3497 Learn more about TestLens at testlens.app. |
Description
What was found
What changed
VirtualThreadPromiseFactoryin grails-async-corePromiseFactoryBuilderwith opt-in configOut of scope / follow-up
Related MD topics
Contributor Checklist
Issue and Scope
8.0.x.Code Quality
Licensing and Attribution
ai-generated-starting-pointlabel applied.Documentation
Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]