Skip to content

Bound PeerDB CDC work units - #1236

Merged
Asherlc merged 4 commits into
mainfrom
Asherlc/sleep-not-updating
Jun 3, 2026
Merged

Asherlc merged 4 commits into
mainfrom
Asherlc/sleep-not-updating

Conversation

@Asherlc

@Asherlc Asherlc commented Jun 3, 2026

Copy link
Copy Markdown
Owner

Summary

This bounds PeerDB CDC work by lowering mirror CDC batches to 100,000 rows and serializing 100,000-row initial snapshot partitions instead of increasing PeerDB memory.
It adds Postgres logical-slot recovery headroom with six slots/senders and a 16 GiB per-slot WAL cap, plus a manual CDC health command/runbook that is explicitly not a deploy gate.
It records the June 3 stale sleep incident and updates CDC setup tests/docs.

Verification

Passed: docker stack config -c deploy/stack.yml, pnpm lint, pnpm tsc --noEmit, cd packages/server && pnpm tsc --noEmit, cd packages/web && pnpm tsc --noEmit, focused CDC tests, and the previously failing router suites after a ClickHouse reset.
Caveat: a clean full pnpm test still failed late in two existing router integration suites because local ClickHouse RSS hit its 3 GiB test cap after 583 files passed.


Summary by cubic

Bounds PeerDB CDC work to 100k-row batches and serialized 100k-row snapshots to stay within fixed memory, and increases Postgres logical replication headroom (6 slots/senders, 16 GiB per-slot WAL). Adds a manual CDC health check and runbook to detect lost slots and stale mirrors, plus docs, tests, and incident notes.

  • New Features

    • pnpm check:clickhouse-cdc script that fails on lost/inactive slots, dangerous retained WAL, or stale _peerdb_synced_at.
    • CDC health runbook with prevention, triage, and recovery steps.
    • Expanded unit tests for the health checker (lost slots, freshness age, numeric parsing, thresholds, safe table-name validation) and CDC setup tests asserting bounded batch/snapshot settings; recorded the June 3 stale sleep incident.
  • Refactors

    • Lowered PeerDB max_batch_size to 100,000 across mirrors; initial snapshot set to 100,000 rows, single worker/table.
    • Postgres deploy: max_replication_slots=6, max_wal_senders=6, max_slot_wal_keep_size=16GB.
    • Docs updated to reflect bounded CDC work units and recovery headroom (plus ClickHouse 13 GiB memory profile); added peerflow to the spell-check dictionary.

Written for commit 1999a36. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Increased PostgreSQL replication slot capacity and WAL retention to reduce lost-slot incidents.
  • Documentation

    • Added ClickHouse CDC health runbook and a production-incident entry describing diagnosis and recovery steps.
  • Chores

    • Added a CLI health-check script and package script to run it.
    • Increased ClickHouse memory guidance and tuned CDC batch/snapshot sizing (100,000 rows) for safer recovery.
  • Tests

    • Added comprehensive CDC health tests and mirror-configuration assertions.

Copilot AI review requested due to automatic review settings June 3, 2026 20:39

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Asherlc, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a ClickHouse CDC health-check implementation (with Zod contracts), CLI integration, tests, PeerDB mirror throttling (100k batches + snapshot controls), Postgres replication-slot/WAL retention increases, and runbook/incident documentation.

Changes

ClickHouse CDC Health Monitoring and Incident Recovery

Layer / File(s) Summary
Infrastructure baseline and WAL retention tuning
deploy/stack.yml, deploy/README.md
Postgres max_replication_slots and max_wal_senders increased to 6; max_slot_wal_keep_size increased to 16GB. Deploy README updated for ClickHouse memory and PeerDB persistence paths.
CDC health-check module with Zod validation
src/db/clickhouse-cdc-health.ts
Exports checkClickHouseCdcHealth() and assertClickHouseCdcHealth(). Validates/normalizes numeric fields, queries pg_replication_slots and ClickHouse mirror freshness, and classifies failures/warnings into a CdcHealthReport.
CDC health-check test suite
src/db/clickhouse-cdc-health.test.ts
Vitest suite with fake Postgres/ClickHouse clients and builders; covers healthy, missing/lost/inactive slots, retained-WAL thresholds, stale mirrors, parsing errors, and security name-validation.
CLI script and npm script registration
scripts/check-clickhouse-cdc.ts, package.json, scripts/README.md
Adds scripts/check-clickhouse-cdc.ts CLI that runs the health check, logs per-issue output, asserts results, and exits with non-zero on failure. Registered as pnpm check:clickhouse-cdc and documented.
PeerDB CDC batch size and snapshot throttling
src/db/peerdb/metric-stream-cdc.sql, src/db/clickhouse-cdc.test.ts
Reduces max_batch_size from 1,000,000 to 100,000 for metric-stream and raw mirrors; adds snapshot_num_rows_per_partition=100000, snapshot_max_parallel_workers=1, snapshot_num_tables_in_parallel=1. Tests updated to assert these settings.
Operations runbook and incident baseline
docs/clickhouse-cdc-health-runbook.md, docs/production-incident-baseline.md, docs/README.md, cspell.json
Adds a ClickHouse CDC health runbook (prevention, triage, recovery), records a 2026-06-03 lost-slot incident with remediation steps and tuning (16GB retention, 100k work units), updates docs index, and adds peerflow to cspell.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Asherlc/dofek#1098: Touches PeerDB→ClickHouse CDC mirror configuration related to this PR's mirror tuning.
  • Asherlc/dofek#1080: Introduced the metric-stream CDC pipeline this PR monitors and tunes.
  • Asherlc/dofek#1089: Related edits to metric-stream-cdc.sql that overlap the mirror definitions adjusted here.

Suggested labels

area/infra, area/db, type/feature

Suggested reviewers

  • cubic-dev-ai
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning Title is in imperative mood, 27 characters (under 70), and directly describes the main change (bounding PeerDB CDC work units), but lacks a required area prefix. Add an area prefix such as [deploy] or [server] to align with the requirement: e.g., '[deploy] Bound PeerDB CDC work units' or '[server] Bound PeerDB CDC work units'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Storybook previews for 858ad929 are ready:

This comment updates automatically on each PR push.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/db/clickhouse-cdc.test.ts (1)

376-384: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the throttling knobs on each raw mirror, not on an aggregated string.

These assertions still pass if dofek_provider_inventory_raw_analytics or dofek_sensor_priority_raw_analytics lose the new settings while dofek_fitness_raw_analytics keeps them. The SQL change touched all three mirrors, so the test should check each rendered CREATE MIRROR statement separately.

Also applies to: 1211-1224

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/clickhouse-cdc.test.ts` around lines 376 - 384, The test currently
concatenates peerDbQueries into rawMirrorSql and asserts throttling settings
once, which can mask missing settings on individual mirrors; instead iterate
over the rendered CREATE MIRROR statements and assert the three throttling knobs
are present for each raw analytics mirror. Locate where peerDbQueries and
rawAnalyticsTables are used (variables rawMirrorSql, peerDbQueries,
rawAnalyticsTables) and change the assertions to, for each rawAnalyticsTable,
find the specific CREATE MIRROR SQL (e.g., the corresponding peerDbQueries
element that contains `from: fitness.${rawAnalyticsTable}` / `to:
${rawAnalyticsTable}`) and assert it contains "max_batch_size = 100000",
"snapshot_num_rows_per_partition = 100000", "snapshot_max_parallel_workers = 1",
and "snapshot_num_tables_in_parallel = 1"; apply the same fix to the other
occurrence around the 1211-1224 test block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@deploy/README.md`:
- Around line 53-54: The README's ClickHouse memory-limit bullet is stale:
update the text to reflect that the service container memory limit and
checked-in server config now use 13G (not 3500 MiB / 3 GiB) and that the stack
mounts the `clickhouse_memory_limits_13g` config from `deploy/stack.yml`; also
confirm mention of the checked-in `max_server_memory_usage` cap matches the 13G
profile name and note that Docker Swarm configs are immutable so you must rotate
the config key (e.g., `clickhouse_memory_limits_13g`) when changing contents.

In `@docs/clickhouse-cdc-health-runbook.md`:
- Around line 75-76: Inline the mirror-to-table mapping into the runbook so
operators don't need to open source files; copy the exported mapping (the
constant or function in the ClickHouse CDC module that maps mirror names to
destination table names) from the ClickHouse CDC implementation and place it
directly in the runbook (or add a clear link to another human-maintained docs
page that contains that same mapping). Ensure the mapping uses the same
identifiers as in the CDC code (the exported constant/function that assembles
destination tables) and add a short note indicating the mapping version or
last-sync commit so the runbook remains self-contained and auditable.
- Around line 100-125: Update the recovery steps to use the repo's scripted,
env-loading runner instead of bare node and raw source filenames: replace the
`node ... src/db/setup-clickhouse-cdc.ts` invocation with the repo wrapper
`./scripts/with-env.sh tsx src/db/setup-clickhouse-cdc.ts` so
`.env.local`/Infisical secrets are loaded, and change the follow-up instruction
that references `scripts/check-clickhouse-cdc.ts` to the package task `pnpm
check:clickhouse-cdc` (or the equivalent npm script) so operators run the
TypeScript automation through `pnpm tsx` consistently.

In `@scripts/check-clickhouse-cdc.ts`:
- Around line 18-27: The initialization of Postgres and ClickHouse clients
(Client construction using requireEnvironmentVariable("DATABASE_URL") and
createClickHouseClientFromEnv()) happens before the try/catch in main(), so
configuration errors escape your handled path; move creation of postgresClient
and clickHouseClient into the try block inside main() (after Sentry.init) so any
thrown errors are caught and sent to captureException(), set exitCode, and go
through the shared failure handling; also make cleanup logic (where
postgresClient.end or clickHouse client close is called) tolerate
partially-initialized clients (check for non-null/defined before calling
close/end) and ensure missing prerequisites fail with explicit environment key
names (use requireEnvironmentVariable exactly as the source of the DATABASE_URL
error message).

In `@src/db/clickhouse-cdc-health.test.ts`:
- Around line 107-184: Add a test that exercises the inactive-slot branch by
calling checkHealth with healthySlotRows() modified via withSlotOverride to set
active: false for a required slot (e.g.,
"peerflow_slot_dofek_fitness_raw_analytics"), then assert the returned
report.issues contains a failure entry describing the inactive replication slot
(matching addSlotIssues() behavior) and that assertClickHouseCdcHealth(report)
throws; place this alongside the other it(...) cases using the same helpers
(checkHealth, healthySlotRows, withSlotOverride, assertClickHouseCdcHealth).

---

Outside diff comments:
In `@src/db/clickhouse-cdc.test.ts`:
- Around line 376-384: The test currently concatenates peerDbQueries into
rawMirrorSql and asserts throttling settings once, which can mask missing
settings on individual mirrors; instead iterate over the rendered CREATE MIRROR
statements and assert the three throttling knobs are present for each raw
analytics mirror. Locate where peerDbQueries and rawAnalyticsTables are used
(variables rawMirrorSql, peerDbQueries, rawAnalyticsTables) and change the
assertions to, for each rawAnalyticsTable, find the specific CREATE MIRROR SQL
(e.g., the corresponding peerDbQueries element that contains `from:
fitness.${rawAnalyticsTable}` / `to: ${rawAnalyticsTable}`) and assert it
contains "max_batch_size = 100000", "snapshot_num_rows_per_partition = 100000",
"snapshot_max_parallel_workers = 1", and "snapshot_num_tables_in_parallel = 1";
apply the same fix to the other occurrence around the 1211-1224 test block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ff3291df-f339-44b5-a7a4-ead0497b08d9

📥 Commits

Reviewing files that changed from the base of the PR and between ad06f20 and a2eadec.

📒 Files selected for processing (12)
  • deploy/README.md
  • deploy/stack.yml
  • docs/README.md
  • docs/clickhouse-cdc-health-runbook.md
  • docs/production-incident-baseline.md
  • package.json
  • scripts/README.md
  • scripts/check-clickhouse-cdc.ts
  • src/db/clickhouse-cdc-health.test.ts
  • src/db/clickhouse-cdc-health.ts
  • src/db/clickhouse-cdc.test.ts
  • src/db/peerdb/metric-stream-cdc.sql

Comment thread deploy/README.md Outdated
Comment thread docs/clickhouse-cdc-health-runbook.md Outdated
Comment thread docs/clickhouse-cdc-health-runbook.md
Comment thread scripts/check-clickhouse-cdc.ts Outdated
Comment thread src/db/clickhouse-cdc-health.test.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: The PR modifies production-critical Postgres replication settings and PeerDB mirror batch sizes, which directly impact data pipeline stability and recovery behavior, making it unsuitable for auto-approval despite the documentation and low-risk script additions.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 1 file (changes from recent commits).

Requires human review: The PR modifies critical production PostgreSQL replication configuration and PeerDB mirror SQL, which could impact database behavior and data replication pipeline integrity, requiring human review.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 13 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Requires human review: The PR modifies critical production PostgreSQL replication settings (slots, senders, WAL cap) and PeerDB batch sizes, which directly affect replication reliability and resource usage; even small misconfigurations could cause data loss or infrastructure strain, so a human should review these changes.

Re-trigger cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/clickhouse-cdc-health-runbook.md (1)

86-103: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Mismatched example slot/mirror names across recovery steps.

Step 2 drops mirror dofek_fitness_raw_analytics, but Step 3's drop-slot example targets peerflow_slot_dofek_metric_stream_analytics — the slot for a different mirror (dofek_fitness_raw_analytics's slot would be peerflow_slot_dofek_fitness_raw_analytics). Mid-incident, an operator copy-pasting these consecutively could drop the wrong slot. Align the example identifiers within the walk-through (or add a single ${MIRROR} placeholder note).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/clickhouse-cdc-health-runbook.md` around lines 86 - 103, The example
uses mismatched identifiers: Step 2 drops mirror dofek_fitness_raw_analytics but
Step 3's slot example targets peerflow_slot_dofek_metric_stream_analytics (a
different mirror); update the docs so the slot name matches the mirror (use
peerflow_slot_dofek_fitness_raw_analytics) or replace both concrete examples
with a single ${MIRROR} placeholder and show how to derive the slot name
(peerflow_slot_${MIRROR}) to prevent copy-paste errors; ensure the mirror name
dofek_fitness_raw_analytics and the slot pattern
peerflow_slot_dofek_fitness_raw_analytics are consistent across steps.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@docs/clickhouse-cdc-health-runbook.md`:
- Around line 86-103: The example uses mismatched identifiers: Step 2 drops
mirror dofek_fitness_raw_analytics but Step 3's slot example targets
peerflow_slot_dofek_metric_stream_analytics (a different mirror); update the
docs so the slot name matches the mirror (use
peerflow_slot_dofek_fitness_raw_analytics) or replace both concrete examples
with a single ${MIRROR} placeholder and show how to derive the slot name
(peerflow_slot_${MIRROR}) to prevent copy-paste errors; ensure the mirror name
dofek_fitness_raw_analytics and the slot pattern
peerflow_slot_dofek_fitness_raw_analytics are consistent across steps.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 268ddb6c-9240-4b75-b511-09e515abd20f

📥 Commits

Reviewing files that changed from the base of the PR and between a2eadec and 1999a36.

📒 Files selected for processing (5)
  • cspell.json
  • deploy/README.md
  • docs/clickhouse-cdc-health-runbook.md
  • scripts/check-clickhouse-cdc.ts
  • src/db/clickhouse-cdc-health.test.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Requires human review: This PR changes production PostgreSQL replication slot and WAL retention settings (max_slot_wal_keep_size from 4GB to 16GB, slot count from 4 to 6) and reduces PeerDB CDC batch sizes from 1M to 100K rows, which are infrastructure and data pipeline changes with potential impact on database resource,

Re-trigger cubic

@Asherlc
Asherlc merged commit 061eaaf into main Jun 3, 2026
71 checks passed
@Asherlc
Asherlc deleted the Asherlc/sleep-not-updating branch June 3, 2026 22:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants