Queries icon
IonToJson icon
Script icon
Process icon
Query icon
If icon
JsonToIon icon
BulkInsert icon
Log icon
Trigger icon

Stream PostgreSQL orders into ClickHouse with replay-safe updates and deletes

Stream Postgres orders into ClickHouse with Debezium, versioned updates, retained deletes, replay protection and per-batch read-back checks.

Categories
Data

Mirror PostgreSQL orders in ClickHouse without Kafka or nightly reloads.

How it works

  1. Debezium polls WAL every 30 seconds and snapshots existing orders once.
  2. Validate records and retain the latest source LSN per key.
  3. JDBC reads existing versions; equal replays and older events are skipped. Conflicting equal versions fail before insertion.
  4. An If runs a prepared BulkInsert only for newer keys.
  5. Verify each key and delete marker. orders_live uses FINAL before filtering deletes; background merges are not required.

What you get

  • A current-state view; tombstones prevent old batches resurrecting deletes.
  • Per-batch verification, not racy comparisons with a changing source table.
  • Saved files for recovery. Partial retries can leave duplicate physical versions: this is at-least-once, not a distributed transaction.

Who it's for

Data engineers maintaining a small, near-real-time analytics read model.

Why orchestrate this with Kestra

Capture, JDBC writes and verification share one execution. Queued concurrency serializes batches; failures retain evidence.

Prerequisites

  • Postgres with wal_level=logical, REPLICATION and SELECT. Pre-create CREATE PUBLICATION kestra_clickhouse_orders FOR TABLE public.orders as table owner. Use a dedicated slot, flow and empty target, with no other target writers. maxRecords does not bound the initial snapshot.
  • Source: public.orders (id bigint PRIMARY KEY, customer_id bigint NOT NULL, amount_cents bigint NOT NULL, status varchar(32) NOT NULL).
  • ClickHouse create/insert/select privileges; Python 3 on workers for the Process runner. No Python packages needed.

Secrets

  • CDC_POSTGRES_USERNAME, CDC_POSTGRES_PASSWORD: replication connection.
  • CLICKHOUSE_USERNAME, CLICKHOUSE_PASSWORD: target credentials.

Quick start

  1. Create the source table/publication; set secrets and connection variables.
  2. Save the flow. Check the snapshot; then insert, update and delete orders. Read default.orders_live after each successful execution.
  3. On failure the trigger disables. Restart the failed execution, or replay its original Ion file through replay_file, before enabling capture again. Offsets advance at capture, not sink success; do not discard failed batches.
  4. For full-source parity, stop writes, drain capture and compare all rows.

How to extend

Add columns to the validator, target and bindings together. Do not truncate the source, reset offsets or purge tombstones: rebuild together instead. DDL is not replicated; unexpected columns or incomplete values fail closed.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.