Imp.Deadline (Imp v0.5.0)

Copy Markdown View Source

Process-scoped absolute deadlines for cooperative time budgets.

A deadline is either :infinity or an absolute monotonic time in milliseconds. with_deadline/2 binds one to the calling process for the duration of a function; a nested with_deadline/2 can shorten the bound but never extend it.

The bound is cooperative: only code that reads it is limited by it. Imp.Clients.ReqLLM caps each request's :receive_timeout and :total_timeout (retries included) to the time left, and Imp.Predict.ReActV2 makes no further model request once it has passed. Apart from Imp's own evaluation and optimizer machinery, nothing is limited by it: a running tool or retriever is not interrupted. To stop work at a time you choose, run it in a process you can cancel, such as a run from Imp.start_run/3.

The binding belongs to the calling process. Work Imp starts in other processes carries it: every Imp.Tasks task, and so Imp.parallel/3, evaluation rows, optimizer fan-out and Imp.Run, runs under the deadline of the process that started it. Imp.Run.start/3 also takes deadline:, and Imp.Evaluate's :deadline option and GEPA's coordinator bind their own in the workers they start, and stop those workers when it passes. Each of these is resolved with resolve/1, so it can shorten the inherited deadline but never extend it. The deadline does not bound the wait for a place in Imp's task pool; Imp.Run.start/3 returns {:error, :deadline_exceeded} instead of starting a run whose deadline passed while it waited. A process started with plain spawn/1 or Task carries nothing; call with_deadline/2 inside it with {:deadline, current()} captured in the parent.

Summary

Functions

Returns the deadline bound to the current process, or :infinity.

Whether deadline has expired.

Milliseconds until deadline expires (:infinity never does), floored at 0.

Resolves a timeout to an absolute deadline, capped by the current process deadline. Accepts :infinity, a relative timeout in milliseconds, or an already-absolute {:deadline, absolute}.

Runs fun with the resolved deadline bound to the current process, restoring the previous binding afterwards.

Types

t()

@type t() :: :infinity | integer()

Functions

current()

@spec current() :: t()

Returns the deadline bound to the current process, or :infinity.

expired?(deadline)

@spec expired?(t()) :: boolean()

Whether deadline has expired.

remaining(absolute)

@spec remaining(t()) :: :infinity | non_neg_integer()

Milliseconds until deadline expires (:infinity never does), floored at 0.

resolve(timeout)

@spec resolve(:infinity | non_neg_integer() | {:deadline, integer()}) :: t()

Resolves a timeout to an absolute deadline, capped by the current process deadline. Accepts :infinity, a relative timeout in milliseconds, or an already-absolute {:deadline, absolute}.

with_deadline(timeout, fun)

@spec with_deadline(
  :infinity | non_neg_integer() | {:deadline, integer()},
  (-> result)
) :: result
when result: var

Runs fun with the resolved deadline bound to the current process, restoring the previous binding afterwards.