Class EquinixAsync

java.lang.Object
com.eqixiac.equinix.core.async.EquinixAsync
All Implemented Interfaces:
AutoCloseable

public final class EquinixAsync extends Object implements AutoCloseable
A small, generic asynchronous facade over any Equinix SDK call, backed by Java 21 virtual threads. Rather than mirroring the entire API surface with ...Async variants, this runs an arbitrary blocking SDK call on a virtual thread and hands the caller a CompletableFuture, so a single small class covers Fabric, NetworkEdge, CustomerPortal and every other domain.

Each submitted call runs on its own virtual thread from Executors.newVirtualThreadPerTaskExecutor(). Virtual threads are cheap and park (rather than pin a platform thread) while a request is blocked on I/O, so thousands of concurrent SDK calls can be in flight without an explicit thread-pool size to tune.

Usage

try (EquinixAsync async = EquinixAsync.create()) {
    CompletableFuture<Connection> f = async.call(() -> fabric.connections().getByUuid(id));
    CompletableFuture<Void> v = async.run(() -> fabric.connections().getByUuid(id).delete());

    // Fan out, then join:
    List<CompletableFuture<Connection>> futures = ids.stream()
            .map(id -> async.call(() -> fabric.connections().getByUuid(id)))
            .toList();
    List<Connection> connections = EquinixAsync.awaitAll(futures);
}

Exceptions thrown by the supplied call (for example an EquinixServiceException or any other RuntimeException) are not swallowed: the returned future completes exceptionally with the original throwable as its cause, surfaced through CompletableFuture.join() / CompletableFuture.get() as usual.

This class is AutoCloseable; closing it shuts down the backing executor and waits (up to a bounded grace period) for in-flight calls to finish, so exiting a try-with-resources block does not silently abandon submitted work. Calls submitted after close() are rejected. Instances are thread-safe and intended to be shared, typically for the lifetime of the work being parallelised.

Author:
ianjones
  • Method Details

    • create

      public static EquinixAsync create()
      Creates a new facade backed by a fresh virtual-thread-per-task executor.
      Returns:
      a new EquinixAsync; close it (ideally via try-with-resources) when done
    • call

      public <T> CompletableFuture<T> call(Supplier<T> apiCall)
      Runs a value-returning SDK call asynchronously on a virtual thread.

      If apiCall throws, the returned future completes exceptionally with that throwable as the cause; otherwise it completes with the supplied result (which may be null).

      Type Parameters:
      T - the result type of the call
      Parameters:
      apiCall - the blocking SDK call to run, e.g. () -> fabric.connections().getByUuid(id)
      Returns:
      a future completed with the call's result, or completed exceptionally on error
    • run

      public CompletableFuture<Void> run(Runnable apiCall)
      Runs a void SDK call (for example a delete or update) asynchronously on a virtual thread.

      If apiCall throws, the returned future completes exceptionally with that throwable as the cause; otherwise it completes with null once the call returns.

      Parameters:
      apiCall - the blocking SDK call to run, e.g. () -> connection.delete()
      Returns:
      a future completed when the call returns, or completed exceptionally on error
    • awaitAll

      public static <T> List<T> awaitAll(Collection<? extends CompletableFuture<? extends T>> futures)
      Awaits a collection of futures and collects their results in iteration order. This is a blocking convenience for the common "fan out, then join" pattern.

      If any future completes exceptionally, the first such failure (in iteration order) is rethrown as a CompletionException whose cause is the original throwable, exactly as CompletableFuture.join() would surface it. If the calling thread is interrupted while waiting, an AsyncException is thrown and the interrupt flag is restored.

      Type Parameters:
      T - the result type of the futures
      Parameters:
      futures - the futures to await; not modified
      Returns:
      the results in the iteration order of futures
    • close

      public void close()
      Shuts down the backing virtual-thread executor and blocks until in-flight calls finish. New submissions via call(Supplier) or run(Runnable) after this point are rejected.

      In-flight calls are given a bounded grace period (60 seconds) to complete; anything still running after that is interrupted via ExecutorService.shutdownNow(). Virtual threads are daemon threads, so without this wait a fire-and-forget run(...) inside try-with-resources could be silently killed by JVM exit. If the closing thread is itself interrupted while waiting, remaining work is interrupted immediately and the interrupt flag is restored. Idempotent.

      Specified by:
      close in interface AutoCloseable