Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4e58e48
feat: ledger engine — chunk checklist + per-chunk staging, no Redis (…
ar2rsawseen Aug 17, 2026
c0b71cf
bench: kill-drill supports both engines via DRILL_ENGINE
ar2rsawseen Aug 17, 2026
d2ae949
feat: Countly-branded live dashboard for the ledger engine (/viz)
ar2rsawseen Aug 17, 2026
7f85b6c
feat: complete the ledger engine — DLQ, bisection, breaker, backpress…
ar2rsawseen Aug 17, 2026
7845383
refactor: single-architecture service — remove the legacy engine enti…
ar2rsawseen Aug 17, 2026
1505849
fix: honest completion + operator recovery (found by live failure drill)
ar2rsawseen Aug 17, 2026
0d23752
feat: ingestion-matching transform — adopt shared spec + differential…
ar2rsawseen Aug 17, 2026
691609a
fix: per-process dedup-canary table name (multi-pod create/drop race)
ar2rsawseen Aug 17, 2026
fa3d1a2
docs: operational runbook (flow, incident responses, in-place variant)
ar2rsawseen Aug 17, 2026
ed9ef40
feat: poison-pill quarantine — auto-split chunks that crash the process
ar2rsawseen Aug 17, 2026
d0ac2c8
feat: DLQ waive — the terminal operator decision for unmigratable docs
ar2rsawseen Aug 17, 2026
57eb793
feat(viz): full operator console — controls, DLQ panel, coercion report
ar2rsawseen Aug 17, 2026
4d6f710
feat(viz): self-service migration console — guided runbook, preflight…
ar2rsawseen Aug 17, 2026
63413e9
feat: pod scaling UX, real preflight actions, chaos-hardening
ar2rsawseen Aug 17, 2026
58baa64
feat(viz): configuration card — current knobs, defaults, when-to-chan…
ar2rsawseen Aug 18, 2026
87c5478
fix: null-cd sweep ordering — close a silent data-miss window (found …
ar2rsawseen Aug 18, 2026
c9d5620
docs+setup: fresh-operator path — compose/.env rewritten, README spli…
ar2rsawseen Aug 18, 2026
b4da411
feat(viz): serve the console at / — /viz kept as alias
ar2rsawseen Aug 18, 2026
7ebcd8c
fix(engine): a startup failure no longer kills the console
ar2rsawseen Aug 18, 2026
9cf0073
feat: ledger rebuild from data + per-collection scoping of all live c…
ar2rsawseen Aug 18, 2026
d461d94
feat(k8s): ready-to-apply Kubernetes manifests
ar2rsawseen Aug 18, 2026
0e2c34c
docs: decouple the transform spec from the unmerged platform PR
ar2rsawseen Aug 18, 2026
82d4783
docs: reference countly-platform#1105 (surgical cd passthrough)
ar2rsawseen Aug 18, 2026
900e016
feat(verify): attribute duplicate ids to live ingestion vs migration
ar2rsawseen Aug 18, 2026
68cfe26
feat: migrated provenance flag — 100% exact migrated/live distinction
ar2rsawseen Aug 18, 2026
622dcf3
refactor: provenance without schema changes — (_id, cd) pairs replace…
ar2rsawseen Aug 18, 2026
081afc4
ci: run the full integration suite on every PR (MongoDB 7 + ClickHous…
ar2rsawseen Aug 18, 2026
2243004
fix(viz): honest counters + DLQ fix-location guidance
ar2rsawseen Aug 18, 2026
2575422
feat: scale-proof UI + self-driving preflight
ar2rsawseen Aug 18, 2026
06e4782
feat: billion-scale engine paths — async verify, partitioned dup scan…
ar2rsawseen Aug 18, 2026
43fa12d
config: default SERVICE_NAME to drill-migrator — two required vars, n…
ar2rsawseen Aug 18, 2026
930f9aa
test: migration under concurrent live ingestion
ar2rsawseen Aug 18, 2026
2f6d87d
feat: mass-DLQ safety — global pause guard, background replay, redo-t…
ar2rsawseen Aug 18, 2026
c801daa
feat(dlq): mass guard and panel report the disk cost
ar2rsawseen Aug 18, 2026
d7dbef0
fix(viz): replay toast says started, not finished
ar2rsawseen Aug 18, 2026
f2759d0
feat: optional dashboard auth (DASHBOARD_PASSWORD)
ar2rsawseen Aug 18, 2026
c78e2df
Revert dashboard auth — not needed
ar2rsawseen Aug 18, 2026
8fa6c2a
docs: Docker multi-container scaling recipe
ar2rsawseen Aug 18, 2026
9652804
feat: post-migration audits — source recount + sampled doc-per-doc co…
ar2rsawseen Aug 20, 2026
363cc63
feat: per-commit source-count guard + cd-pruned id lookups
ar2rsawseen Aug 20, 2026
5e71394
fix(audit): waived/pending DLQ docs explain their window's shortfall
ar2rsawseen Aug 20, 2026
a78df1a
test: de-flake live-parallel writer assertion
ar2rsawseen Aug 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 29 additions & 64 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,67 +1,32 @@
# ─── Service ───
SERVICE_NAME=mongo-to-clickhouse-migrator
SERVICE_PORT=8080
SERVICE_HOST=0.0.0.0
GRACEFUL_SHUTDOWN_TIMEOUT_MS=60000
RERUN_MODE=resume

# ─── MongoDB Source ───
MONGO_URI=mongodb://localhost:27017/?replicaSet=rs0
MONGO_DB=countly_drill
MONGO_COLLECTION_PREFIX=drill_events
MONGO_READ_PREFERENCE=primary
MONGO_READ_CONCERN=majority
MONGO_RETRY_READS=true
MONGO_APP_NAME=mongo-to-clickhouse-migrator
MONGO_BATCH_ROWS_TARGET=10000
MONGO_CURSOR_BATCH_SIZE=2000
MONGO_MAX_TIME_MS=120000

# ─── Transform ───
TRANSFORM_VERSION=v1

# ─── ClickHouse Target ───
# ─── Required (the only two you must set) ───
MONGO_URI=mongodb://localhost:27017
CLICKHOUSE_URL=http://localhost:8123

# ─── Common ───
#SERVICE_NAME=drill-migrator
SERVICE_PORT=8080
MONGO_DB=countly_drill # source database with drill_events* collections
MONGO_COUNTLY_DB=countly # for per-event collection-hash resolution
CLICKHOUSE_DB=countly_drill
CLICKHOUSE_TABLE=drill_events
CLICKHOUSE_USERNAME=default
CLICKHOUSE_PASSWORD=
CLICKHOUSE_QUERY_TIMEOUT_MS=120000
CLICKHOUSE_MAX_RETRIES=8
CLICKHOUSE_RETRY_BASE_DELAY_MS=1000
CLICKHOUSE_RETRY_MAX_DELAY_MS=30000
CLICKHOUSE_USE_DEDUP_TOKEN=true

# ─── Backpressure ───
BACKPRESSURE_ENABLED=true
BACKPRESSURE_PARTS_TO_THROW_INSERT=300
BACKPRESSURE_MAX_PARTS_IN_TOTAL=500
BACKPRESSURE_PARTITION_PCT_HIGH=0.50
BACKPRESSURE_PARTITION_PCT_LOW=0.35
BACKPRESSURE_TOTAL_PCT_HIGH=0.50
BACKPRESSURE_TOTAL_PCT_LOW=0.40
BACKPRESSURE_POLL_INTERVAL_MS=15000
BACKPRESSURE_MAX_PAUSE_EPISODE_MS=180000

# ─── State ───
MANIFEST_DB=countly_drill
REDIS_URL=redis://redis:6379
REDIS_KEY_PREFIX=mig
TIMELINE_SNAPSHOT_INTERVAL=10

# ─── Memory / GC ───
GC_ENABLED=true
GC_RSS_SOFT_LIMIT_MB=1536
GC_RSS_HARD_LIMIT_MB=2048
GC_HEAP_USED_RATIO=0.70
GC_EVERY_N_BATCHES=10

# ─── Logging ───
LOG_LEVEL=info

# ─── Lifecycle ───
# When true, the service shuts down cleanly (exit 0) once all collections
# finish migrating. Used by one-shot orchestration (e.g. docker compose
# --abort-on-container-exit). Default false: service stays running with
# dashboard available.
EXIT_ON_COMPLETE=false
MANIFEST_DB=countly_drill # where progress state lives: mig_ranges + mig_dlq_docs
# (recoverable if lost: dashboard → Help & Recovery → Rebuild ledger from data)
# Read preference is AUTO: on a replica set the engine picks
# secondaryPreferred by itself (source is frozen after cutover, so secondary
# reads are exact). Set explicitly only to override:
#MONGO_READ_PREFERENCE=primary

# ─── Run identity & scaling ───
LEDGER_RUN_ID=migration-1 # stable resume key — keep it the same across restarts
#POD_ID=pod-1 # unique per instance when running multiple pods
#EXIT_ON_COMPLETE=true # exit 0 when all chunks are done (one-shot orchestration)

# ─── Sizing (see the UI's Configuration card for guidance) ───
#LEDGER_CHUNK_DOCS_TARGET=2000000
#LEDGER_MAX_CHUNK_DAYS=7
#MONGO_PAGE_SIZE=10000
#LEDGER_INSERT_INFLIGHT=3

# ─── Rehearsal ───
#DRY_RUN=true # sampled rehearsal, nothing stored (or use the UI button)
#DRY_RUN_SAMPLE_PCT=2
78 changes: 78 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: CI

on:
push:
branches: [main]
pull_request:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
unit:
name: Typecheck + differential harness
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '25'
cache: npm

- name: Install dependencies
run: npm ci

- name: Typecheck
run: npm run typecheck

# Asserts src/transform/ reproduces countly-platform's live ingestion
# normalization exactly (vendored goldens in tests/differential/).
# Pure unit tests — no MongoDB/ClickHouse/Redis required.
- name: Ingestion-matching differential harness
run: npx vitest run tests/differential

integration:
name: Integration (MongoDB 7 + ClickHouse 26.4)
runs-on: ubuntu-latest
services:
mongo:
image: mongo:7
ports: ['27017:27017']
options: >-
--health-cmd "mongosh --quiet --eval 'db.runCommand({ping:1})'"
--health-interval 5s --health-timeout 5s --health-retries 30
clickhouse:
# Production ClickHouse version (deploy/compose/images.standard.env
# in countly-platform). 26.4 requires a password for non-localhost
# clients — the tests read TEST_CLICKHOUSE_PASSWORD.
image: clickhouse/clickhouse-server:26.4
env:
CLICKHOUSE_PASSWORD: ci-pass
ports: ['8123:8123']
options: >-
--health-cmd "clickhouse-client --password ci-pass --query 'SELECT 1'"
--health-interval 5s --health-timeout 5s --health-retries 30
env:
TEST_CLICKHOUSE_PASSWORD: ci-pass
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '25'
cache: npm

- name: Install dependencies
run: npm ci

# Full engine suite: ledger store semantics, e2e chunk pipeline with
# DLQ/coercions/null-cd sweep, multi-collection scoping regressions,
# ledger rebuild, duplicate attribution, pair-based attach recovery.
- name: Integration tests
run: npx vitest run tests/integration
Loading
Loading