Interface AsyncScope

All Superinterfaces:
AutoCloseable
All Known Implementing Classes:
DefaultAsyncScope

public interface AsyncScope extends AutoCloseable
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 Type
    Method
    Description
    <T> Awaitable<T>
    async(Supplier<T> supplier)
    Launches a child task within this scope.
    void
    Cancels all child tasks.
    void
    Closes the scope, waiting for all child tasks to complete.
    static AsyncScope
    Creates a new scope with the default executor and fail-fast enabled.
    static AsyncScope
    create(Executor executor)
    Creates a new scope with the given executor and fail-fast enabled.
    static AsyncScope
    create(Executor executor, boolean failFast)
    Creates a new scope with the given executor and failure policy.
    static AsyncScope
    Returns the scope currently bound to this thread, or null.
    int
    Returns the number of tracked child tasks (including completed ones that have not yet been pruned).
    Returns the parent scope, or null if this is a root scope.
    static <T> T
    withCurrent(AsyncScope scope, Supplier<T> supplier)
    Executes the supplier with the given scope installed as current, restoring the previous binding afterwards.
    static <T> T
    Creates a scope with a timeout.
    static <T> T
    withScope(Executor executor, Duration timeout, Function<AsyncScope,T> body)
    Creates a scope with the given executor and a timeout.
    static <T> T
    withScope(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> T
    Creates a scope, executes the body within it, and ensures the scope is closed on exit.
  • Method Details

    • async

      <T> Awaitable<T> async(Supplier<T> supplier)
      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 Awaitable representing the child task
      Throws:
      IllegalStateException - if the scope has already been closed
    • getParent

      AsyncScope getParent()
      Returns the parent scope, or null if 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:
      close in interface AutoCloseable
    • current

      static AsyncScope current()
      Returns the scope currently bound to this thread, or null.
    • withCurrent

      static <T> T withCurrent(AsyncScope scope, Supplier<T> supplier)
      Executes the supplier with the given scope installed as current, restoring the previous binding afterwards.
    • withScope

      static <T> T withScope(Function<AsyncScope,T> body)
      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

      static <T> T withScope(Executor executor, Function<AsyncScope,T> body)
      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 tasks
      body - the function to execute within the scope
      Returns:
      the body's return value
    • withScope

      static <T> T withScope(Duration timeout, Function<AsyncScope,T> body) throws TimeoutException
      Creates a scope with a timeout. If the body does not complete within the specified duration, all child tasks are cancelled and the scope throws TimeoutException.
      Type Parameters:
      T - the result type
      Parameters:
      timeout - the maximum duration for the scope
      body - 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 TimeoutException
      Creates a scope with the given executor and a timeout.
      Type Parameters:
      T - the result type
      Parameters:
      executor - the executor for child tasks
      timeout - the maximum duration for the scope
      body - the function to execute within the scope
      Returns:
      the body's return value
      Throws:
      TimeoutException - if the timeout expires
      Since:
      6.0.0
    • create

      static AsyncScope create()
      Creates a new scope with the default executor and fail-fast enabled.
    • create

      static AsyncScope create(Executor executor)
      Creates a new scope with the given executor and fail-fast enabled.
    • create

      static AsyncScope create(Executor executor, boolean failFast)
      Creates a new scope with the given executor and failure policy.