Package groovy.concurrent
Interface AsyncScope
- All Superinterfaces:
AutoCloseable
- All Known Implementing Classes:
DefaultAsyncScope
A structured concurrency scope that ensures all child tasks complete
(or are cancelled) before the scope exits.
AsyncScope provides a bounded lifetime for async tasks,
following the structured concurrency model. Unlike
fire-and-forget async { ... }, tasks launched within a scope
are guaranteed to complete before the scope closes. This prevents:
- Orphaned tasks that outlive their logical parent
- Resource leaks from uncollected async work
- Silent failures from unobserved exceptions
By default, the scope uses a fail-fast policy: when any child task completes exceptionally, all sibling tasks are cancelled immediately. The first failure becomes the primary exception; subsequent failures are added as suppressed exceptions.
def results = AsyncScope.withScope { scope ->
def userTask = scope.async { fetchUser(id) }
def orderTask = scope.async { fetchOrders(id) }
return [user: await(userTask), orders: await(orderTask)]
}
// Both tasks guaranteed complete here
- Since:
- 6.0.0
- See Also:
-
Method Summary
Modifier and TypeMethodDescription<T> Awaitable<T>Launches a child task within this scope.voidCancels all child tasks.voidclose()Closes the scope, waiting for all child tasks to complete.static AsyncScopecreate()Creates a new scope with the default executor and fail-fast enabled.static AsyncScopeCreates a new scope with the given executor and fail-fast enabled.static AsyncScopeCreates a new scope with the given executor and failure policy.static AsyncScopecurrent()Returns the scope currently bound to this thread, ornull.intReturns the number of tracked child tasks (including completed ones that have not yet been pruned).Returns the parent scope, ornullif this is a root scope.static <T> TwithCurrent(AsyncScope scope, Supplier<T> supplier) Executes the supplier with the given scope installed as current, restoring the previous binding afterwards.static <T> TwithScope(Duration timeout, Function<AsyncScope, T> body) Creates a scope with a timeout.static <T> TwithScope(Executor executor, Duration timeout, Function<AsyncScope, T> body) Creates a scope with the given executor and a timeout.static <T> TwithScope(Executor executor, Function<AsyncScope, T> body) Creates a scope with the given executor, executes the body, and ensures the scope is closed on exit.static <T> TwithScope(Function<AsyncScope, T> body) Creates a scope, executes the body within it, and ensures the scope is closed on exit.
-
Method Details
-
async
Launches a child task within this scope. The task's lifetime is bound to the scope: when the scope is closed, all incomplete child tasks are cancelled.- Type Parameters:
T- the result type- Parameters:
supplier- the task body to execute- Returns:
- an
Awaitablerepresenting the child task - Throws:
IllegalStateException- if the scope has already been closed
-
getParent
AsyncScope getParent()Returns the parent scope, ornullif this is a root scope.When a scope is created inside another scope (via
withScope(java.util.function.Function<groovy.concurrent.AsyncScope, T>)), the outer scope becomes the parent. Cancelling a parent scope propagates cancellation to all child scopes.- Returns:
- the parent scope, or
null - Since:
- 6.0.0
-
getChildCount
int getChildCount()Returns the number of tracked child tasks (including completed ones that have not yet been pruned). -
cancelAll
void cancelAll()Cancels all child tasks. -
close
void close()Closes the scope, waiting for all child tasks to complete. If any child failed and fail-fast is enabled, remaining children are cancelled and the first failure is rethrown.- Specified by:
closein interfaceAutoCloseable
-
current
Returns the scope currently bound to this thread, ornull. -
withCurrent
Executes the supplier with the given scope installed as current, restoring the previous binding afterwards. -
withScope
Creates a scope, executes the body within it, and ensures the scope is closed on exit. The body receives the scope as its argument for launching child tasks.// Java: var result = AsyncScope.withScope(scope -> { var a = scope.async(() -> computeA()); var b = scope.async(() -> computeB()); return List.of(AsyncSupport.await(a), AsyncSupport.await(b)); }); // Groovy (Closure overload added via extension method): def result = AsyncScope.withScope { scope -> def a = scope.async { computeA() } def b = scope.async { computeB() } return [await(a), await(b)] }- Type Parameters:
T- the result type- Parameters:
body- the function to execute within the scope- Returns:
- the body's return value
-
withScope
Creates a scope with the given executor, executes the body, and ensures the scope is closed on exit.- Type Parameters:
T- the result type- Parameters:
executor- the executor for child tasksbody- the function to execute within the scope- Returns:
- the body's return value
-
withScope
Creates a scope with a timeout. If the body does not complete within the specified duration, all child tasks are cancelled and the scope throwsTimeoutException.- Type Parameters:
T- the result type- Parameters:
timeout- the maximum duration for the scopebody- the function to execute within the scope- Returns:
- the body's return value
- Throws:
TimeoutException- if the timeout expires- Since:
- 6.0.0
-
withScope
static <T> T withScope(Executor executor, Duration timeout, Function<AsyncScope, T> body) throws TimeoutExceptionCreates a scope with the given executor and a timeout.- Type Parameters:
T- the result type- Parameters:
executor- the executor for child taskstimeout- the maximum duration for the scopebody- the function to execute within the scope- Returns:
- the body's return value
- Throws:
TimeoutException- if the timeout expires- Since:
- 6.0.0
-
create
Creates a new scope with the default executor and fail-fast enabled. -
create
Creates a new scope with the given executor and fail-fast enabled. -
create
Creates a new scope with the given executor and failure policy.
-