Class LazyResolution<T>

java.lang.Object
dev.langchain4j.agentic.internal.LazyResolution<T>
Type Parameters:
T - the type of the resolved value

public final class LazyResolution<T> extends Object
A value resolved lazily, the first time it is needed, from something that may be unavailable or slow, like the server of a remote agent.

The value is resolved by one attempt at a time, and every caller needing the value meanwhile waits on that attempt instead of making its own. When the attempt fails, the callers waiting on it all fail with its failure, and the failure is not cached: the next call starts a new attempt.

Without a timeout, the caller starting the attempt resolves the value itself, on its own thread: no thread of the LangChain4j executor is needed, which a bounded one may not have left when its threads are the callers waiting for this value. Interrupting that caller interrupts the resolution, so the callers waiting on it fail with it.

An attempt given a timeout, counted from its start, runs instead on a thread of the LangChain4j executor, with the context of the caller starting it, so that it can be abandoned. At that deadline the callers waiting on it fail with a TimeoutException and the thread resolving the value is interrupted. The attempt stays the current one until that thread really ends: a call arriving in the meantime fails at once with a LazyResolution.StillRunningException, so that the value is never resolved twice at the same time, and a value resolved after the deadline is kept for the next call. A warning is logged at the deadline, and when a value resolved after it is kept.

  • Constructor Details

    • LazyResolution

      public LazyResolution(Supplier<String> description, Supplier<T> resolver)
      Parameters:
      description - says what is resolved in the warnings logged for an attempt that outlives its timeout, like "the agent card of A2A agent 'x'": it is asked only when such a warning is logged
      resolver - resolves the value, on a thread of the LangChain4j executor when the attempt has a timeout and on the one of the caller starting it otherwise: it returns a non-null value or throws an unchecked exception, and it is released once the value is resolved
  • Method Details

    • resolved

      public static <T> LazyResolution<T> resolved(T value)
      Returns:
      a resolution whose value is already known
    • peek

      public T peek()
      Returns:
      the value if it has already been resolved, null otherwise: it never resolves it
    • get

      public T get(Duration timeout) throws InterruptedException, TimeoutException
      Returns the value, resolving it first if needed, or waiting for the attempt that is already resolving it.
      Parameters:
      timeout - the time given to the attempt started by this call, or null or zero for no limit: a call joining an attempt already started waits until the deadline of that attempt
      Returns:
      the resolved value
      Throws:
      RuntimeException - the failure of the attempt, the same instance for every caller waiting on it
      TimeoutException - when the attempt did not resolve the value within its timeout, and a LazyResolution.StillRunningException when it did not before this call, and its thread has not ended yet
      InterruptedException - when the calling thread is interrupted while waiting, which does not stop the attempt: only the caller resolving the value itself, when there is no timeout, has the resolution interrupted with it
    • describe

      public static String describe(Duration timeout)
      How a timeout is shown in the messages of the failures reporting it, like 30 s or 200 ms.