acilox / solutions / cross-cloud-data-sync
☁️ Platform Integrations

Cross-Cloud Data Sync

Plugin-driven data movement across AWS, Azure, GCP, Snowflake, Postgres and Oracle. Each connector implements the same five-method interface; jobs configured via UI wizard or YAML.

0
Built-in connectors
10,000 rows
Default batch size
APScheduler
Scheduler
SSE
Live run viewer

Why this exists

Most data teams accumulate a long tail of one-off scripts that copy data between systems — Postgres-to-Snowflake replication, S3-to-Azure DR mirroring, BigQuery-to-Oracle bridges for legacy reports, ad-hoc migrations. This consolidates that work into a single application a non-engineer can configure and operate, with a real connector interface underneath instead of script soup.

How it's wired together

operator

deltas / errors

6 built-in connectors — one interface

S3

Azure Blob

BigQuery

Snowflake

Postgres

Oracle

Flask wizard

YAML job def

job spec
(source · target · schedule · CDC)

APScheduler
(in-process)

source connector
read (batch=10K)

target connector
write

reconciliation
row-count + schema

job result

SSE stream
live run viewer

Cross-Cloud Data Sync architecture overview

How it works, end-to-end

  1. One Connector interface, six implementations

    AWS S3, Azure Blob, GCP BigQuery, Snowflake, PostgreSQL and Oracle each implement the same five methods — connect, close, read, write, validate. New connectors are 200 lines, not a rewrite.

  2. Job configuration via UI wizard or YAML

    Operators define source, target, schedule and CDC watermark through a Flask wizard; engineers edit the YAML directly. Both produce the same canonical job record.

  3. APScheduler in-process orchestration

    Jobs run on APScheduler in the same Python process — no Airflow dependency, no separate scheduler service. Default batch size 10,000 rows; pluggable for memory-constrained sources.

  4. Live run viewer via Server-Sent Events

    Each run streams progress, error events, and reconciliation deltas to a browser via SSE — no polling, no WebSocket complexity. Operators see the same view in real time that the job is writing to its log.

The choices that matter

Decision

APScheduler in-process, not Airflow

For 50 jobs and one operator team, Airflow is over-architecture. APScheduler runs in the same process as Flask, deploys as one container, and is sufficient up to roughly 200 jobs.

No backfill UI; backfills are a manual job-trigger. Acceptable at this scale; escape hatch is documented (swap APScheduler for an Airflow operator that calls the same Connector interface).

Decision

CDC watermark via timestamp or full-table hash

Timestamp watermarks work for most operational tables; full-table hash works for small dimension tables without a reliable timestamp.

Hash-CDC reads the full source each run. Flagged in the README; documented limit at ~10M rows.

Decision

No RBAC by default — proxy auth instead

Most teams deploy this behind their SSO proxy (oauth2-proxy, Cloudflare Access). Re-implementing auth inside the app is a maintenance tax with no marginal security benefit.

Decision

Row-count + schema reconciliation, not row-by-row

Catches the bugs that matter (counts mismatch, columns lost) without doubling the data volume. Column-distribution checks are on the roadmap behind an opt-in flag.

Built on

Python 3.11FlaskAPSchedulerboto3azure-storage-blobgoogle-cloud-bigquerysnowflake-connectorpsycopg2cx_Oracle