Skip to main content

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

Data Pipeline 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 Filters give you a multi-way decision without inventing a router-of-routers. Each Filter has a KEPT port and a DROP port, and DROP flows into the next Filter, so nothing is thrown away on the way down the chain.

Step-by-step​

#NodeActionKey configurationOutput shape
1StartNoneNoneNone
2SourcePostgreSQL: querySELECT event_id, event_type, payload, occurred_at FROM events WHERE occurred_at > now() - interval '6 minutes'.Event row
3FilterNoneRule: event_type equals TXN_SETTLED. KEPT -> Snowflake path. DROP -> downstream Filter.Same row, routed
4Transform (Snowflake path)NoneMap payload.amount and payload.currency to scalar columns.Snowflake-shaped row
5Load: SnowflakeSnowflake: AppendTarget WH.FACT.TXN_SETTLED.None
6Filter (second)NoneRule: event_type equals TXN_WARNING. KEPT -> S3. DROP (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.None
8ReshapeNoneBuild 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.None

Variations​

  • More than three targets: chain another Filter (or use a Router node, which has five route ports plus a default) for an N-way decision.
  • Different DB family: swap the Source for MSSQL / MySQL / Oracle / Snowflake. The Filter rules stay identical.
  • Send all three event types to S3 too: add a Fork right after Source, then run the existing Filter 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.