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

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}. A LAYERING, for display and for staging a whole-cell rerun. The cascade's actual rule is "pop a cell with no pending upstream" (Cascade.shallowest/2); depth is one witness to it, not the rule itself.
  • 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 (captured by the payload write that produced the change).

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 "*".