Posets
A Poset (partially ordered set) is a directed acyclic graph (DAG) where nodes are Events and edges represent causal relationships. If event A caused event B, there is an edge from A to B. Events with no causal connection are considered independent, meaning they may have happened concurrently or in any relative order.
Building a Causal Graph
Create a Poset, add events, and declare which events caused which. The caused_by parameter accepts a list of predecessor events.
1from pyrapide import Event, Poset
2
3poset = Poset()
4
5request = Event(name="api.request", payload={"endpoint": "/data"})
6poset.add(request)
7
8db_query = Event(name="db.query", payload={"sql": "SELECT *"})
9poset.add(db_query, caused_by=[request])
10
11cache_check = Event(name="cache.check", payload={"key": "data"})
12poset.add(cache_check, caused_by=[request])
13
14assert poset.are_independent(db_query, cache_check)
15assert poset.is_ancestor(request, db_query)
In this example, the request event causes both db_query and cache_check. Because neither the database query nor the cache check caused the
other, they are independent; they could have executed concurrently.
Querying Relationships
The Poset API provides several methods for exploring causal structure:
is_ancestor(a, b): returnsTrueifacausally precedesb(directly or transitively).is_descendant(a, b): returnsTrueifais causally afterb.are_independent(a, b): returnsTrueif neither event is an ancestor of the other.predecessors(e): returns the set of events that directly causede.successors(e): returns the set of events directly caused bye.ancestors(e): returns all transitive ancestors ofe.descendants(e): returns all transitive descendants ofe.
Cycle Prevention
CausalCycleError immediately.The Poset enforces the DAG invariant on every add() call. This means you can always
trust that the causal graph is well-formed, regardless of the order in which events arrive.
from pyrapide import Event, Poset, CausalCycleError
poset = Poset()
a = Event(name="a", payload={})
b = Event(name="b", payload={})
poset.add(a)
poset.add(b, caused_by=[a])
try:
poset.add(a, caused_by=[b]) # Would create a cycle
except CausalCycleError as e:
print(f"Cycle detected: {e}")
Partial Order Semantics
The "partial" in partially ordered set is key. Unlike a total order (where every pair of elements is comparable), a Poset only orders events that are causally related. Two independent events have no defined order, and that is by design. This faithfully models the reality of distributed systems where concurrent operations have no inherent ordering.
For higher-level management of events including clock tracking and query utilities, see Computations.