Interface Awaitable<T>

Type Parameters:
T - the result type
All Known Implementing Classes:
GroovyPromise

public interface Awaitable<T>
Core abstraction for asynchronous computations in Groovy.

Awaitable represents a computation that may not have completed yet. It serves as both an instance type (the result of async methods and the input to await) and a static API surface for combinators, factories, and configuration.

Static combinators (all return Awaitable, suitable for use with await). Multi-argument await desugars to Awaitable.all(...), so await(a, b) and await a, b are shorthand for await Awaitable.all(a, b):

Static factories and conversion:

Instance continuations provide ergonomic composition without exposing raw CompletableFuture APIs:

Third-party frameworks (RxJava, Reactor, etc.) can integrate by registering an AwaitableAdapter via AwaitableAdapterRegistry.

The default implementation, GroovyPromise, delegates to CompletableFuture but users never need to depend on that detail.

Since:
6.0.0
See Also:
  • Method Summary

    Modifier and Type
    Method
    Description
    all(Object... sources)
    Returns an Awaitable that completes when all given sources complete successfully, with a list of their results in order.
    allSettled(Object... sources)
    Returns an Awaitable that completes when all given sources have settled (succeeded or failed), with a list of AwaitResult objects describing each outcome.
    static <T> Awaitable<T>
    any(Object... sources)
    Returns an Awaitable that completes when the first of the given sources completes, with the winner's result.
    boolean
    Attempts to cancel the computation.
    static <T> Awaitable<T>
    completeOnTimeout(Object source, T fallback, long duration, TimeUnit unit)
    Adapts the given source and returns a new awaitable that yields the supplied fallback value if the timeout expires first.
    default Awaitable<T>
    completeOnTimeout(T fallback, long duration, TimeUnit unit)
    Returns a new Awaitable that completes with the supplied fallback value if this computation does not finish before the timeout expires.
    static <T> Awaitable<T>
    completeOnTimeoutMillis(Object source, T fallback, long timeoutMillis)
    Adapts the given source and returns a new awaitable that yields the supplied fallback value if the timeout expires first.
    default Awaitable<T>
    completeOnTimeoutMillis(T fallback, long timeoutMillis)
    Returns a new Awaitable that completes with the supplied fallback value if this computation does not finish before the timeout expires.
    static Awaitable<Void>
    delay(long milliseconds)
    Returns an Awaitable that completes after the specified delay.
    static Awaitable<Void>
    delay(long duration, TimeUnit unit)
    Returns an Awaitable that completes after the specified delay.
    Returns a new Awaitable that, if this one completes exceptionally, applies the given function to the exception to produce a recovery value.
    static <T> Awaitable<T>
    Returns an already-failed Awaitable with the given exception.
    static <T> Awaitable<T>
    first(Object... sources)
    Returns an Awaitable that completes with the result of the first source that succeeds.
    static <T> Awaitable<T>
    from(Object source)
    Converts the given source to an Awaitable.
    get()
    Blocks until the computation completes and returns the result.
    get(long timeout, TimeUnit unit)
    Blocks until the computation completes or the timeout expires.
    static Executor
    Returns the current executor used for async operations.
    static <T> Awaitable<T>
    go(Closure<T> closure)
    Spawns a lightweight task.
    default <U> Awaitable<U>
    handle(BiFunction<? super T,Throwable,? extends U> fn)
    Returns a new Awaitable that handles both the successful and the exceptional completion paths in a single continuation.
    boolean
    Returns true if the computation was cancelled before completing normally.
    boolean
    Returns true if this computation completed exceptionally (including cancellation).
    boolean
    Returns true if the computation has completed (normally, exceptionally, or via cancellation).
    static boolean
    Returns true if the running JVM supports virtual threads (JDK 21+).
    static <T> Awaitable<T>
    of(T value)
    Returns an already-completed Awaitable with the given value.
    default Awaitable<T>
    orTimeout(long duration, TimeUnit unit)
    Returns a new Awaitable that fails with TimeoutException if this computation does not complete within the specified duration.
    static <T> Awaitable<T>
    orTimeout(Object source, long duration, TimeUnit unit)
    Adapts the given source and applies a non-blocking fail-fast timeout with explicit TimeUnit.
    default Awaitable<T>
    orTimeoutMillis(long timeoutMillis)
    Returns a new Awaitable that fails with TimeoutException if this computation does not complete within the specified milliseconds.
    static <T> Awaitable<T>
    orTimeoutMillis(Object source, long timeoutMillis)
    Adapts the given source to an Awaitable and applies a non-blocking fail-fast timeout.
    static void
    Sets the executor to use for async operations.
    <U> Awaitable<U>
    then(Function<? super T,? extends U> fn)
    Returns a new Awaitable whose result is obtained by applying the given function to this awaitable's result when it completes.
    default Awaitable<Void>
    thenAccept(Consumer<? super T> action)
    Returns a new Awaitable that, when this one completes normally, invokes the given consumer and completes with null.
    <U> Awaitable<U>
    thenCompose(Function<? super T,? extends Awaitable<U>> fn)
    Returns a new Awaitable produced by applying the given async function to this awaitable's result, flattening the nested Awaitable.
    Converts this Awaitable to a JDK CompletableFuture for interoperability with APIs that require it.
    default Awaitable<T>
    whenComplete(BiConsumer<? super T,? super Throwable> action)
    Returns a new Awaitable that invokes the given action when this computation completes, regardless of success or failure.
    static <T> T
    withScope(Closure<T> body)
    Convenience delegate to AsyncScope.withScope(Closure).
  • Method Details

    • get

      Blocks until the computation completes and returns the result.
      Returns:
      the computed result
      Throws:
      InterruptedException - if the calling thread is interrupted while waiting
      ExecutionException - if the computation completed exceptionally
    • get

      Blocks until the computation completes or the timeout expires.
      Parameters:
      timeout - the maximum time to wait
      unit - the time unit of the timeout argument
      Returns:
      the computed result
      Throws:
      InterruptedException - if the calling thread is interrupted while waiting
      ExecutionException - if the computation completed exceptionally
      TimeoutException - if the wait timed out
    • isDone

      boolean isDone()
      Returns true if the computation has completed (normally, exceptionally, or via cancellation).
      Returns:
      true if complete
    • cancel

      boolean cancel()
      Attempts to cancel the computation. If the computation has not yet started or is still running, it will be cancelled with a CancellationException.
      Returns:
      true if the computation was successfully cancelled
    • isCancelled

      boolean isCancelled()
      Returns true if the computation was cancelled before completing normally.
      Returns:
      true if cancelled
    • isCompletedExceptionally

      boolean isCompletedExceptionally()
      Returns true if this computation completed exceptionally (including cancellation).
      Returns:
      true if completed with an error or cancellation
    • then

      <U> Awaitable<U> then(Function<? super T,? extends U> fn)
      Returns a new Awaitable whose result is obtained by applying the given function to this awaitable's result when it completes.
      Type Parameters:
      U - the type of the mapped result
      Parameters:
      fn - the mapping function
      Returns:
      a new awaitable holding the mapped result
    • thenCompose

      <U> Awaitable<U> thenCompose(Function<? super T,? extends Awaitable<U>> fn)
      Returns a new Awaitable produced by applying the given async function to this awaitable's result, flattening the nested Awaitable. This is the monadic flatMap operation for awaitables.
      Type Parameters:
      U - the type of the inner awaitable's result
      Parameters:
      fn - the async mapping function that returns an Awaitable
      Returns:
      a new awaitable holding the inner result
    • thenAccept

      default Awaitable<Void> thenAccept(Consumer<? super T> action)
      Returns a new Awaitable that, when this one completes normally, invokes the given consumer and completes with null.

      Useful at API boundaries where you need to attach logging, metrics, or other side effects without blocking for the result.

      Parameters:
      action - the side-effecting consumer to invoke on success
      Returns:
      a new awaitable that completes after the action runs
      Since:
      6.0.0
    • exceptionally

      Awaitable<T> exceptionally(Function<Throwable,? extends T> fn)
      Returns a new Awaitable that, if this one completes exceptionally, applies the given function to the exception to produce a recovery value. The throwable passed to the function is deeply unwrapped to strip JDK wrapper layers.
      Parameters:
      fn - the recovery function
      Returns:
      a new awaitable that recovers from failures
    • whenComplete

      default Awaitable<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
      Returns a new Awaitable that invokes the given action when this computation completes, regardless of success or failure.

      The supplied throwable is transparently unwrapped so handlers see the original failure rather than ExecutionException / CompletionException wrappers.

      Parameters:
      action - the completion callback receiving the result or failure
      Returns:
      a new awaitable that completes with the original result
      Since:
      6.0.0
    • handle

      default <U> Awaitable<U> handle(BiFunction<? super T,Throwable,? extends U> fn)
      Returns a new Awaitable that handles both the successful and the exceptional completion paths in a single continuation.

      The supplied throwable is transparently unwrapped so the handler sees the original failure. This provides a single place for success/failure projection, combining both paths in one callback.

      Type Parameters:
      U - the projected result type
      Parameters:
      fn - the handler receiving either the value or the failure
      Returns:
      a new awaitable holding the handler's result
      Since:
      6.0.0
    • orTimeoutMillis

      default Awaitable<T> orTimeoutMillis(long timeoutMillis)
      Returns a new Awaitable that fails with TimeoutException if this computation does not complete within the specified milliseconds.

      Unlike get(long, TimeUnit), this is a non-blocking, composable timeout combinator: it returns another Awaitable that can itself be awaited, chained, or passed to all(Object...) / any(Object...).

      Parameters:
      timeoutMillis - the timeout duration in milliseconds
      Returns:
      a new awaitable with timeout semantics
      Since:
      6.0.0
    • orTimeout

      default Awaitable<T> orTimeout(long duration, TimeUnit unit)
      Returns a new Awaitable that fails with TimeoutException if this computation does not complete within the specified duration.
      Parameters:
      duration - the timeout duration
      unit - the time unit
      Returns:
      a new awaitable with timeout semantics
      Since:
      6.0.0
    • completeOnTimeoutMillis

      default Awaitable<T> completeOnTimeoutMillis(T fallback, long timeoutMillis)
      Returns a new Awaitable that completes with the supplied fallback value if this computation does not finish before the timeout expires.
      Parameters:
      fallback - the value to use when the timeout expires
      timeoutMillis - the timeout duration in milliseconds
      Returns:
      a new awaitable that yields either the original result or the fallback
      Since:
      6.0.0
    • completeOnTimeout

      default Awaitable<T> completeOnTimeout(T fallback, long duration, TimeUnit unit)
      Returns a new Awaitable that completes with the supplied fallback value if this computation does not finish before the timeout expires.
      Parameters:
      fallback - the value to use when the timeout expires
      duration - the timeout duration
      unit - the time unit
      Returns:
      a new awaitable that yields either the original result or the fallback
      Since:
      6.0.0
    • toCompletableFuture

      CompletableFuture<T> toCompletableFuture()
      Converts this Awaitable to a JDK CompletableFuture for interoperability with APIs that require it.
      Returns:
      a CompletableFuture representing this computation
    • from

      static <T> Awaitable<T> from(Object source)
      Converts the given source to an Awaitable.

      If the source is already an Awaitable, it is returned as-is. Otherwise, the AwaitableAdapterRegistry is consulted to find a suitable adapter. Built-in adapters handle CompletableFuture, CompletionStage, and Future; third-party frameworks can register additional adapters via the registry.

      This is the recommended entry point for converting external async types to Awaitable:

       Awaitable<String> aw = Awaitable.from(someCompletableFuture)
       Awaitable<Integer> aw2 = Awaitable.from(someReactorMono)
       
      Type Parameters:
      T - the result type
      Parameters:
      source - the source object; if null, returns a completed awaitable with a null result
      Returns:
      an awaitable backed by the source
      Throws:
      IllegalArgumentException - if no adapter supports the source type
      Since:
      6.0.0
      See Also:
      • AwaitableAdapterRegistry.toAwaitable(Object)
    • of

      static <T> Awaitable<T> of(T value)
      Returns an already-completed Awaitable with the given value. Useful for returning a pre-computed result from an API that requires an Awaitable return type.
      Type Parameters:
      T - the result type
      Parameters:
      value - the result value (may be null)
      Returns:
      a completed awaitable
    • failed

      static <T> Awaitable<T> failed(Throwable error)
      Returns an already-failed Awaitable with the given exception.

      Useful for signaling a synchronous error from an API that returns Awaitable, without spawning a thread:

       if (id < 0) return Awaitable.failed(new IllegalArgumentException("negative id"))
       
      Type Parameters:
      T - the nominal result type (never produced, since the awaitable is failed)
      Parameters:
      error - the exception to wrap; must not be null
      Returns:
      an immediately-failed awaitable
      Throws:
      NullPointerException - if error is null
    • go

      static <T> Awaitable<T> go(Closure<T> closure)
      Spawns a lightweight task.

      Type Parameters:
      T - the result type
      Parameters:
      closure - the task body
      Returns:
      an awaitable representing the spawned task
      Since:
      6.0.0
    • withScope

      static <T> T withScope(Closure<T> body)
      Convenience delegate to AsyncScope.withScope(Closure). Creates a structured concurrency scope, executes the closure within it, and ensures all child tasks complete before returning.
      Type Parameters:
      T - the result type
      Parameters:
      body - the closure receiving the scope
      Returns:
      the closure's return value
      Since:
      6.0.0
      See Also:
    • all

      static Awaitable<List<Object>> all(Object... sources)
      Returns an Awaitable that completes when all given sources complete successfully, with a list of their results in order.

      Like JavaScript's Promise.all(), the combined awaitable fails as soon as the first source fails. Remaining sources are not cancelled automatically; cancel them explicitly if that is required by your workflow.

      Unlike blocking APIs, this returns immediately and the caller should await the result. All three forms below are equivalent:

       // Explicit all() call
       def results = await Awaitable.all(task1, task2, task3)
      
       // Parenthesized multi-arg await — syntactic sugar
       def results = await(task1, task2, task3)
      
       // Unparenthesized multi-arg await — most concise form
       def results = await task1, task2, task3
       
      Parameters:
      sources - the awaitables, futures, or adapted objects to wait for
      Returns:
      an awaitable that resolves to a list of results
    • any

      static <T> Awaitable<T> any(Object... sources)
      Returns an Awaitable that completes when the first of the given sources completes, with the winner's result.
       def winner = await Awaitable.any(task1, task2)
       
      Parameters:
      sources - the awaitables to race
      Returns:
      an awaitable that resolves to the first completed result
    • first

      static <T> Awaitable<T> first(Object... sources)
      Returns an Awaitable that completes with the result of the first source that succeeds. Individual failures are silently absorbed; only when all sources have failed does the returned awaitable reject with an IllegalStateException whose suppressed array contains every individual error.

      This is the Groovy equivalent of JavaScript's Promise.any(). Contrast with any(Object...) which returns the first result to complete regardless of success or failure.

      Typical use cases:

      • Hedged requests — send the same request to multiple endpoints, use whichever responds first successfully
      • Graceful degradation — try a primary data source, then a fallback, then a cache, accepting the first success
      • Redundant queries — send the same query to different database replicas for improved latency
       // Hedged HTTP request
       def response = await Awaitable.first(
           fetchFromPrimary(),
           fetchFromFallback(),
           fetchFromCache()
       )
       
      Type Parameters:
      T - the result type
      Parameters:
      sources - the awaitables to race for first success; must not be null, empty, or contain null elements
      Returns:
      an awaitable that resolves with the first successful result
      Throws:
      IllegalArgumentException - if sources is null, empty, or contains null elements
      Since:
      6.0.0
      See Also:
    • allSettled

      static Awaitable<List<AwaitResult<Object>>> allSettled(Object... sources)
      Returns an Awaitable that completes when all given sources have settled (succeeded or failed), with a list of AwaitResult objects describing each outcome.

      Never throws for individual failures; they are captured in the result list.

       def results = await Awaitable.allSettled(task1, task2)
       results.each { println it.success ? it.value : it.error }
       
      Parameters:
      sources - the awaitables to settle
      Returns:
      an awaitable that resolves to a list of settled results
    • delay

      static Awaitable<Void> delay(long milliseconds)
      Returns an Awaitable that completes after the specified delay. Does not block any thread; the delay is handled by a scheduled executor.
       await Awaitable.delay(1000)  // pause for 1 second
       
      Parameters:
      milliseconds - the delay in milliseconds (must be ≥ 0)
      Returns:
      an awaitable that completes after the delay
    • delay

      static Awaitable<Void> delay(long duration, TimeUnit unit)
      Returns an Awaitable that completes after the specified delay.
      Parameters:
      duration - the delay duration (must be ≥ 0)
      unit - the time unit
      Returns:
      an awaitable that completes after the delay
    • orTimeoutMillis

      static <T> Awaitable<T> orTimeoutMillis(Object source, long timeoutMillis)
      Adapts the given source to an Awaitable and applies a non-blocking fail-fast timeout. Returns a new awaitable that fails with TimeoutException if the source does not complete before the deadline elapses.

      The source may be a Groovy Awaitable, a JDK CompletableFuture/CompletionStage, or any type supported by AwaitableAdapterRegistry. This provides a concise timeout combinator that returns another awaitable rather than requiring structural timeout blocks.

      Type Parameters:
      T - the result type
      Parameters:
      source - the async source to time out
      timeoutMillis - the timeout duration in milliseconds
      Returns:
      a new awaitable with timeout semantics
      Since:
      6.0.0
    • orTimeout

      static <T> Awaitable<T> orTimeout(Object source, long duration, TimeUnit unit)
      Adapts the given source and applies a non-blocking fail-fast timeout with explicit TimeUnit.
      Type Parameters:
      T - the result type
      Parameters:
      source - the async source to time out
      duration - the timeout duration
      unit - the time unit
      Returns:
      a new awaitable with timeout semantics
      Since:
      6.0.0
    • completeOnTimeoutMillis

      static <T> Awaitable<T> completeOnTimeoutMillis(Object source, T fallback, long timeoutMillis)
      Adapts the given source and returns a new awaitable that yields the supplied fallback value if the timeout expires first.
      Type Parameters:
      T - the result type
      Parameters:
      source - the async source to wait for
      fallback - the fallback value to use on timeout
      timeoutMillis - the timeout duration in milliseconds
      Returns:
      a new awaitable yielding either the original result or the fallback
      Since:
      6.0.0
    • completeOnTimeout

      static <T> Awaitable<T> completeOnTimeout(Object source, T fallback, long duration, TimeUnit unit)
      Adapts the given source and returns a new awaitable that yields the supplied fallback value if the timeout expires first.
      Type Parameters:
      T - the result type
      Parameters:
      source - the async source to wait for
      fallback - the fallback value to use on timeout
      duration - the timeout duration
      unit - the time unit
      Returns:
      a new awaitable yielding either the original result or the fallback
      Since:
      6.0.0
    • getExecutor

      static Executor getExecutor()
      Returns the current executor used for async operations.

      On JDK 21+, the default is a virtual-thread-per-task executor. On JDK 17–20, a bounded cached daemon thread pool is used (size controlled by the groovy.async.parallelism system property, default 256).

      This method is thread-safe and may be called from any thread.

      Returns:
      the current executor, never null
      See Also:
    • setExecutor

      static void setExecutor(Executor executor)
      Sets the executor to use for async operations.

      Pass null to reset to the default executor. The change takes effect immediately for all subsequent async method invocations; tasks already in flight continue using the executor that launched them.

      This method is thread-safe and may be called from any thread.

      Parameters:
      executor - the executor to use, or null to restore the default executor
      See Also:
    • isVirtualThreadsAvailable

      static boolean isVirtualThreadsAvailable()
      Returns true if the running JVM supports virtual threads (JDK 21+).

      When virtual threads are available, the default executor uses a virtual-thread-per-task strategy that scales to millions of concurrent tasks with minimal memory overhead.

      Returns:
      true if virtual threads are available