skuld_durable

View Source

EffectLogger & SerializableCoroutine > | Umbrella →

Durable execution for Skuld — pause-serialize-resume workflows and effect-level execution logging. Build computations that can survive process restarts, server reboots, and deployment cycles.

What's included

  • Skuld.Effects.EffectLogger — intercepts every effect invocation across all handlers and records it in a flat, JSON-serializable log. Enables three modes: replay (short-circuit completed effects), resume (continue a suspended computation from where it left off), and rerun (re-execute failed computations). Flat log structure preserves ordering even when continuations are discarded by Throw.
  • Skuld.SerializableCoroutine — wraps a coroutine with EffectLogger installed innermost. Handles all lifecycle states: fresh start (run until first yield), live resume (pass a value to a suspended fiber), and cold resume (replay the log, then apply a resume value). serialize and deserialize convert logs to/from JSON for storage.

Installation

def deps do
  [
    {:skuld_durable, "~> 0.32"}
  ]
end

Example: durable order checkout

alias Skuld.SerializableCoroutine

sc = SerializableCoroutine.new(CheckoutWizard.run(), fn comp ->
  comp |> State.with_handler(%{cart: []}) |> Yield.with_handler() |> Throw.with_handler()
end)

# Start — runs until the first Yield
suspended = SerializableCoroutine.run(sc)

# Persist to your database
json = SerializableCoroutine.serialize(SerializableCoroutine.get_log(suspended))
MyApp.Repo.insert_checkout_state(user_id, json)

# --- Server restarts ---

# Deserialize and cold-resume from where we left off
{:ok, log} = SerializableCoroutine.deserialize(json)
SerializableCoroutine.run(log, sc, {:add_item, %{sku: "B-42"}})

Further reading

See the architecture guide for how this fits into the Skuld ecosystem.


EffectLogger & SerializableCoroutine > | Umbrella →