Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Branched Processing

One external feed usually mixes many tenants, customers, or devices. Branches are how Nervix processes those groups independently: when a new group key appears, the branched part of the graph gets its own relay presence and processor state for that group, fully isolated from every other group. See Streams, Branch Keys, And Branches.

This step partitions orders per customer and deduplicates them inside each customer’s branch, so one customer’s duplicates can never suppress another customer’s orders.

Declare The Branch

A branch names its key schema and a TTL. When a branch instance goes idle for the TTL, its branch-local relay and processor state is dropped as a whole (TTL). In an unpaced domain the TTL uses wall clock time.

BEGIN;

CREATE SCHEMA customer_branch (
  customer STRING
);

CREATE BRANCH by_customer SCHEMA customer_branch TTL 5m;

CREATE RELAY orders_by_customer SCHEMA order_record BRANCHED BY by_customer;

CREATE RELAY orders_deduped SCHEMA order_record BRANCHED BY by_customer;

Construct The Branch Key

Only ingestors and reingestors construct branch keys. Since orders is already flowing, a reingestor — a branch-boundary node — re-partitions it without touching the existing graph:

CREATE REINGESTOR partition_orders
  FROM orders
  TO orders_by_customer
    INHERIT ALL
    BRANCHED BY by_customer SET customer = message.customer
    FLUSH EACH 100ms MAX BATCH SIZE 1MiB
    ON MESSAGE ERROR LOG;

BRANCHED BY by_customer SET customer = message.customer builds the concrete key from each record. The first order from a customer materializes that customer’s branch; every relay and processor downstream that declares BRANCHED BY by_customer runs per customer (Branch Semantics).

Deduplicate Per Branch

A deduplicator drops records whose key it has already seen within a time window. Declared BRANCHED BY by_customer, its history is branch-local:

CREATE DEDUPLICATOR dedupe_orders
  FROM orders_by_customer
  DEDUPLICATE ON input.order_id
  MAX TIME 5m
  BRANCHED BY by_customer
  TO orders_deduped
    INHERIT ALL
    FLUSH EACH 250ms MAX BATCH SIZE 1MiB
    ON MESSAGE ERROR LOG;

Emit The Deduplicated Stream

An emitter consumes every concrete branch and collapses branch identity at the external boundary (Branch Semantics) — the Redis channel receives all customers:

CREATE EMITTER redis_deduped
  FROM orders_deduped
  TO REDIS PUBSUB redis_local CHANNEL orders_deduped_out
    MODE NO_ACK RETRY POLICY BACKOFF 250ms MAX 30s
    ENCODE USING order_codec
  INHERIT ALL
  FLUSH EACH 100ms MAX BATCH SIZE 1MiB
  ON MESSAGE ERROR LOG
  ON GENERAL ERROR LOG;

COMMIT;

Prove The Isolation

Subscribe to orders_deduped_out, then produce the same order_id interleaved across two customers:

docker exec redis redis-cli SUBSCRIBE orders_deduped_out
{"order_id":"o-2001","customer":"acme","status":"new","amount":900,"quantity":1}
{"order_id":"o-2001","customer":"globex","status":"new","amount":900,"quantity":1}
{"order_id":"o-2001","customer":"acme","status":"new","amount":900,"quantity":1}

The first two records pass — acme and globex each have their own deduplication history. The third is dropped as a duplicate inside the acme branch only. That is branch isolation: state, batching, and routing for one group never interfere with another. For sizing branched graphs, see Capacity Planning For Branched Graphs.

Next: Error Routes handles records that fail instead of dropping them.