Skip to main content

Example 7: PostgreSQL -> multi-target fan-out with Branch

Workflow examples

Why this example

An events table in PostgreSQL captures every state change in an order-processing system. Three downstream surfaces care about subsets of the stream:

  • Snowflake wants TXN_SETTLED events for BI.
  • S3 wants TXN_WARNING events archived for cold storage.
  • Ops on-call wants an email when a TXN_CRITICAL event lands.

The Branch node is the decision point that routes each row to the right downstream node.

Helix Beverages context: Helix's D2C e-commerce platform writes every state change to a PostgreSQL event store. Settled transactions feed Snowflake for the weekly leadership review, warnings are archived to S3, and critical events page ops on-call. This recipe is the routing core of named problem 5 in the Helix overview: critical events have to reach the right surface within minutes.

At a glance

  • Connectors used: PostgreSQL, Snowflake, AWS S3, SMTP
  • Nodes used: Start, Source, Branch, Transform, Load (x2), Notification
  • Schedule: every 5 minutes
  • Direction: One-way fan-out (PG -> Snowflake, S3, or SMTP)

Canvas

Chained Branches give you a multi-way decision without inventing a router-of-routers; each Branch has TRUE and FALSE outputs, and the FALSE branch flows into the next decision.

Step-by-step

#NodeActionKey configurationOutput shape
1Start------
2SourcePostgreSQL: querySELECT event_id, event_type, payload, occurred_at FROM events WHERE occurred_at > now() - interval '6 minutes'.Event row
3Branch--Predicate: row.event_type === 'TXN_SETTLED'. TRUE port -> Snowflake path. FALSE port -> downstream Branch.Same row, routed
4Transform (Snowflake path)--Map payload.amount and payload.currency to scalar columns.Snowflake-shaped row
5Load: SnowflakeSnowflake: AppendTarget WH.FACT.TXN_SETTLED.--
6Branch (second)--Predicate: row.event_type === 'TXN_WARNING'. TRUE -> S3. FALSE (assumed CRITICAL) -> Notification path.Same row, routed
7Load: S3S3: Upload FileBucket events-cold, key warnings/dt=[occurred_at as yyyy-MM-dd]/[event_id].jsonl. Format JSONL. Append mode.--
8Reshape--Build subject = "Critical event " + row.event_id and body = JSON.stringify(row.payload, null, 2).{ subject, body, recipients }
9NotificationSMTP: Send EmailRecipients from a Variable (\{\{var.global.opsOncallEmail\}\}). Subject + body from the Reshape output.--

Variations

  • More than three targets -- chain another Branch (or use a Router node, which has up to five labeled outputs) for an N-way decision.
  • Different DB family -- swap the Source for MSSQL / MySQL / Oracle / Snowflake. The Branch predicates stay identical.
  • Send all three event types to S3 too -- add a Fork right after Source, then run the existing Branch chain on one Fork output; the other Fork output goes to a single Load: S3 with all events.
  • Replace Notification with PagerDuty webhook -- swap SMTP for the Generic API connector pointed at the PagerDuty Events v2 endpoint.