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
@type t() :: :infinity | integer()
Functions
@spec current() :: t()
Returns the deadline bound to the current process, or :infinity.
Whether deadline has expired.
@spec remaining(t()) :: :infinity | non_neg_integer()
Milliseconds until deadline expires (:infinity never does), floored at 0.
@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}.
@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.