Class BoundedParallelGather

java.lang.Object
org.elasticsearch.xpack.esql.datasources.utils.BoundedParallelGather

public final class BoundedParallelGather extends Object
Applies a function to a list of items with bounded parallelism, collecting results in input order.

Work is routed through a ThrottledTaskRunner, which submits at most maxConcurrency runnables to the provided executor at any one time and holds the remaining items in its own in-memory FIFO queue. This bounds submission, not just execution: a large input list can never overflow a bounded executor queue (e.g. the SEARCH pool), so it can only ever fail fast on a genuine running-slot rejection — never flood the pool with thousands of enqueued tasks. The calling thread blocks until all items complete (join pattern), then returns the results in the same order as the input list. If the calling thread is interrupted while waiting, it short-circuits the not-yet-started items and still drains the in-flight ones before failing, so no task is left running against the executor once gather returns.

Fast-fail semantics: once any item throws, remaining not-yet-started items are skipped (they are still dequeued by the runner but short-circuit before invoking the function). The first exception is re-thrown after all tasks settle. Additional exceptions from other tasks are suppressed onto the first. A running-slot rejection from the executor (surfaced via ActionListener.onFailure(java.lang.Exception)) is recorded the same way, so the call fails fast and cleanly rather than hanging.

Fast-fail granularity is per slot, not per call: an item whose fn invocation is already in progress when the failure (or a cancellation observed inside fn) is seen runs to completion — at most maxConcurrency such calls can be in flight. Only items that have not yet started are skipped. A caller that aborts via a cancellation check inside fn therefore stops promptly, but up to one already-started call per slot may still finish before gather returns.

For zero or one items, the function is executed inline on the calling thread — no thread dispatch occurs. This avoids executor overhead for the common trivial case.

  • Method Details

    • gather

      public static <T, R> List<R> gather(List<T> items, CheckedFunction<T,R,Exception> fn, int maxConcurrency, Executor executor) throws Exception
      Applies fn to each item in items with at most maxConcurrency calls in flight simultaneously. Results are returned in the same order as the input list.
      Type Parameters:
      T - input type
      R - result type
      Parameters:
      items - the inputs to process; must not be null
      fn - the function to apply to each input; may throw any exception
      maxConcurrency - maximum number of concurrent calls; must be >= 1
      executor - the executor used to dispatch work
      Returns:
      a list of results in the same order as items
      Throws:
      Exception - the first exception thrown by any invocation of fn (or by the executor when rejecting a running slot), with remaining exceptions suppressed onto it