ReactiveDag.Drain.Report (reactive_dag v0.16.0)

Copy Markdown View Source

What a drain ACTUALLY did — the processing trace, returned by ReactiveDag.Drain.run/2.

The drain already knows everything worth recording as it works: which cell it claimed, what the recompute reported changed, which cell's propagation caused the work, how long each step took. This struct is that knowledge kept instead of discarded — one entry per recompute step, in execution (topological) order, plus run-level totals.

  • steps — one step/0 per cell recompute, in execution order:
    • :cell — the cell id that recomputed
    • :pass — the drain-loop iteration the step ran in
    • :claimed — the dirty keys claimed (["*"] = whole cell)
    • :changed — the keys the recompute reported as actually changed
    • :triggered_by — the cell whose propagation dirtied this one (nil for the seeded frontier), reconstructing the causal tree
    • :duration_us — microseconds the recompute took
  • passes — drain-loop iterations (≥ length(steps); a pass with an empty claim recomputes nothing)
  • duration_us — wall time of the whole drain

Persistence is deliberately NOT here: the report is a value. A host that wants a durable processing log stores it where its runs already live (an Oban job's meta, a run table) — the library reports; the host records.

Summary

Functions

The causal tree as %{cell => triggered_by}nil roots are the seeded frontier. A cell recomputed more than once keeps its LAST cause (matching the drain's own bookkeeping).

The distinct cells the drain recomputed, in first-touched order.

Total keys reported changed across every step.

Types

step()

@type step() :: %{
  cell: String.t(),
  pass: non_neg_integer(),
  claimed: [String.t()],
  changed: [String.t()],
  triggered_by: String.t() | nil,
  duration_us: non_neg_integer()
}

t()

@type t() :: %ReactiveDag.Drain.Report{
  duration_us: non_neg_integer(),
  passes: non_neg_integer(),
  steps: [step()]
}

Functions

causes(report)

@spec causes(t()) :: %{required(String.t()) => String.t() | nil}

The causal tree as %{cell => triggered_by}nil roots are the seeded frontier. A cell recomputed more than once keeps its LAST cause (matching the drain's own bookkeeping).

cells(report)

@spec cells(t()) :: [String.t()]

The distinct cells the drain recomputed, in first-touched order.

changed_total(report)

@spec changed_total(t()) :: non_neg_integer()

Total keys reported changed across every step.