ReactiveDag.Plan (reactive_dag v0.17.0-rc.52)

Copy Markdown View Source

The compiled DAG plan — pure data the drain executes. Decoupled from any DSL: a host app lowers its declarations into a Cell list and Graph.build/1 produces this. The drain only ever sees the Plan.

  • cells — %{id => Cell}
  • parents — %{child_id => [parent_id]} — forward propagation index (inverse of each cell's inputs); a change to a child enqueues its parents.
  • depths — %{id => longest path from a leaf}; the drain processes cells in ascending depth, so a cell never recomputes while an input is still dirty (topological order, no external scheduler).
  • tenant — which GRAPH this plan is, "*" for a host running one.

Tenant

A host may run the same topology for several independent tenants. Each is its own plan with its own cells, and tenant is what the drain passes to the frontier so its claims, marks and cell selection see only that tenant's work (ReactiveDag.Frontier).

It lives on the PLAN rather than on each cell because it is a property of the run, not of the declaration: the same resource lowers to the same cell in every tenant's plan, which is what makes "the same graph, N times" true rather than approximately true. A cell carries no tenant at all, so nothing about authoring changes.

Summary

Functions

The frontier options for this plan — [tenant: …].

Types

t()

@type t() :: %ReactiveDag.Plan{
  cells: %{required(ReactiveDag.Cell.id()) => ReactiveDag.Cell.t()},
  depths: %{required(ReactiveDag.Cell.id()) => non_neg_integer()},
  parents: %{required(ReactiveDag.Cell.id()) => [ReactiveDag.Cell.id()]},
  tenant: String.t()
}

Functions

frontier_opts(plan)

@spec frontier_opts(t()) :: keyword()

The frontier options for this plan — [tenant: …].

One place builds them, so a call site cannot forget the tenant and silently operate on "*".