One call in a monitored process of its own, its cost counted rather than timed: the
conformance kit's runner (spec/01 §9), ported from visualize's Visualize.Bounded.
The cost is the reductions the call's process spends, collections included, which a
loaded host does not change. A call that answers is judged by its own count, read as
its function returns; a call still running is read every 10 ms and killed at the first
reading over the cap. Liveness is a separate wall-clock bound, timeout, for a call
blocked in receive, which spends no reductions and so is never stopped by a cap.
Nothing is rescued: a raise or an exit is read from the process's :DOWN.
iex> {:ok, 3, _spent} = Macaw.Data.Bounded.run(fn -> 1 + 2 end, timeout: 1_000)
iex> Macaw.Data.Bounded.run(fn -> receive(do: (:never -> :ok)) end, timeout: 10)
:hung
Summary
Functions
thunk called in a process spawned with spawn: options and :monitor, the caller in
its $callers: {:ok, value, reductions}; {:reductions, spent} when it spent more
than reductions: (nil, no cap); :hung when it had not answered within timeout:
ms; {:down, reason} when it exited first, a heap limit's kill as :killed. A process
the caller kills is waited for, so nothing it does outlives the call.
Types
@type outcome() :: {:ok, term(), non_neg_integer()} | {:reductions, non_neg_integer()} | :hung | {:down, term()}
How a bounded call ended.
Functions
thunk called in a process spawned with spawn: options and :monitor, the caller in
its $callers: {:ok, value, reductions}; {:reductions, spent} when it spent more
than reductions: (nil, no cap); :hung when it had not answered within timeout:
ms; {:down, reason} when it exited first, a heap limit's kill as :killed. A process
the caller kills is waited for, so nothing it does outlives the call.