Skuld.Fiber (skuld v0.23.0)

View Source

Cooperative fiber primitive for the FiberPool scheduler.

A Fiber wraps a computation that can be run incrementally, suspended when it yields, and resumed with a value. This is the fundamental building block for cooperative concurrency in Skuld.

Lifecycle

  1. Create with new/2 - fiber is :pending
  2. Run with run_until_suspend/1 - fiber becomes :running, then reaches a terminal or suspended state. All state is captured in the struct:
    • :completed - result and env are set
    • :suspended - suspended_k, env, and optionally internal_suspend are set
    • :error - error and env are set
  3. Resume with resume/2 - suspended fiber runs again until completion/suspension
  4. Cancel with cancel/1 - marks fiber as :cancelled

Usage

Fibers are typically managed by a FiberPool, not used directly. The FiberPool scheduler handles running fibers, tracking suspensions, and resuming when results are available.

State Convention

All fiber state is consolidated in the struct. Callers switch on fiber.status rather than pattern-matching different tuple shapes.

Summary

Functions

Cancel a fiber, invoking leave_scope cleanup for suspended fibers.

Create a new fiber from a computation.

Resume a suspended fiber with a value.

Run a fiber until it completes, suspends, or errors.

Check if a fiber is in a terminal state (completed, cancelled, or error).

Types

status()

@type status() :: :pending | :running | :suspended | :completed | :cancelled | :error

t()

@type t() :: %Skuld.Fiber{
  computation: Skuld.Comp.Types.computation() | nil,
  env: Skuld.Comp.Types.env() | nil,
  error: term(),
  id: reference(),
  internal_suspend: Skuld.Comp.InternalSuspend.t() | nil,
  result: term(),
  status: status(),
  suspended_k: Skuld.Comp.Types.k() | nil
}

Functions

cancel(fiber, reason \\ :cancelled)

@spec cancel(t(), term()) :: t()

Cancel a fiber, invoking leave_scope cleanup for suspended fibers.

For :suspended fibers, creates a %Cancelled{} sentinel and runs it through the leave_scope chain in the fiber's env, giving scoped effects an opportunity to clean up resources. The resulting env is preserved in the cancelled fiber struct.

For :pending fibers, no scopes have been entered yet so no cleanup is needed.

For already-terminal fibers (:completed, :cancelled, :error), cancel is a no-op — the fiber is returned unchanged.

Parameters

  • fiber - The fiber to cancel
  • reason - The cancellation reason (default: :cancelled)

Example

fiber = Fiber.cancel(fiber, :timeout)
assert fiber.status == :cancelled

new(comp, env)

Create a new fiber from a computation.

The fiber starts in :pending status with the computation stored, ready to be run with run_until_suspend/1.

Parameters

  • comp - The computation to run as a fiber
  • env - The environment to run in (typically inherited from parent)

Example

fiber = Fiber.new(my_comp, env)
assert fiber.status == :pending

resume(fiber, value)

@spec resume(t(), term()) :: t()

Resume a suspended fiber with a value.

Takes a :suspended fiber and resumes it by calling the suspended continuation with the provided value. Returns the fiber with updated state — same contract as run_until_suspend/1.

Parameters

  • fiber - A fiber in :suspended status
  • value - The value to resume with (typically a result from an effect)

Example

fiber = Fiber.run_until_suspend(fiber)
# ... later, when we have a result ...
fiber = Fiber.resume(fiber, result)
case fiber.status do
  :completed -> fiber.result
  :suspended -> # suspended again
  :error -> # errored
end

run_until_suspend(fiber)

@spec run_until_suspend(t()) :: t()

Run a fiber until it completes, suspends, or errors.

Takes a :pending fiber and runs its computation. Returns the fiber with all state consolidated in the struct. Callers switch on fiber.status:

  • :completed - fiber.result and fiber.env are set
  • :suspended - fiber.suspended_k and fiber.env are set; fiber.internal_suspend is set for internal suspensions (batch/channel/await)
  • :error - fiber.error and fiber.env are set

The returned fiber (on suspension) can be resumed with resume/2.

Example

fiber = Fiber.new(my_comp, env)
fiber = Fiber.run_until_suspend(fiber)
case fiber.status do
  :completed -> IO.puts("Done: #{inspect(fiber.result)}")
  :suspended -> IO.puts("Suspended, can resume later")
  :error -> IO.puts("Error: #{inspect(fiber.error)}")
end

terminal?(fiber)

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

Check if a fiber is in a terminal state (completed, cancelled, or error).