Query icon
Fail icon
Log icon
If icon
Queries icon
Query icon
Pause icon
Queries icon
LoopUntil icon
Capture icon
IonToJson icon
TransformItems icon
Batch icon
SlackIncomingWebhook icon
Schedule icon

Cut over Oracle tables to PostgreSQL at a frozen SCN

Replicate Oracle to PostgreSQL with Debezium LogMiner, freeze the source at a recorded SCN, drain the last changes and cut over after a checksum match.

Categories
Data

Polling copies miss hard deletes and intermediate updates, so a PostgreSQL replica drifts from Oracle. This flow follows the Oracle redo log and ends with a cutover that is proved instead of assumed.

How it works

SYNC runs the native Debezium Oracle Capture. The first run takes a consistent snapshot and later runs stream changes from offsets kept in the KV store. Each batch is flattened with JSONata and staged in PostgreSQL. One transaction applies the last event per key as an upsert or a delete.

CUTOVER asks for approval through a Pause and rechecks that nothing changed while it waited. It makes both Oracle tables READ ONLY and verifies that. It reads the freeze SCN and loops through Capture and apply until the row count and an MD5 sum of every row match in both databases. Then it writes a COMPLETED cutover record.

ROLLBACK makes the Oracle tables writable again after approval. Offsets stay valid, so SYNC can continue.

What you get

PostgreSQL tables that match Oracle at the freeze and a cutover_log row with the freeze SCN and the last applied SCN. A run that cannot prove the match fails and leaves the source read only.

Who it's for

Teams moving an Oracle schema to PostgreSQL that cannot accept a long read only window or trust a one-off copy.

Why orchestrate this with Kestra

The KV store carries offsets between runs. Pause holds the approval. LoopUntil keeps draining until the proof holds. Restarting a failed execution reuses the captured events, so a failure after Capture loses nothing.

Tested end to end

Kestra 2.0.6 and 2.0.5 with Oracle XE 21c and PostgreSQL 17.5. Writers ran during the snapshot. Updates, deletes and a delete followed by a reinsert arrived as changes. A failed apply was restarted and a killed capture was rerun. Declined and stale approvals, a refused freeze, a parity mismatch that resumed without a new approval and both rollback answers were exercised. Every result was compared row by row with sqlplus and psql.

Prerequisites

Oracle 19c or 21c in ARCHIVELOG mode with minimal and ALL COLUMN supplemental logging on each table. A capture user with the LogMiner grants from the Debezium documentation and an owner account that may run ALTER TABLE READ ONLY. PostgreSQL 13 or later. The Debezium Oracle, JDBC Oracle, JDBC PostgreSQL, Transform JSON, Serdes and Slack plugins.

Secrets

ORACLE_CDC_PASSWORD, ORACLE_APP_PASSWORD, POSTGRES_PASSWORD and SLACK_WEBHOOK_URL.

Inputs

mode selects SYNC, CUTOVER or ROLLBACK. dry_run defaults to true and auto_remediate to false, so nothing changes until both are flipped. capture_seconds and max_records bound each Capture run. The first run must finish the snapshot, so keep both above the largest table.

Quick start

  1. Enable ARCHIVELOG and supplemental logging. Create the capture user.
  2. Set the secrets. Run SYNC as a dry run and read the plan.
  3. Run SYNC with dry_run false and auto_remediate true. Enable the schedule to keep it current.
  4. Stop the writers. Run CUTOVER and approve it. Repoint the applications when it reports COMPLETED.

How to extend

Add a table by copying one table block and its fingerprint. Primary key updates, tables without a primary key and DDL are outside the flow. The fingerprint reads whole tables, so sample very large ones. LogMiner needs the archived logs to stay available between runs.

Links

This blueprint was created by zkasuran.

See How

New to Kestra?

Use blueprints to kickstart your first workflows.