Fix connection pool leak in RunChecks when table validation fails - #105
Conversation
At v1.8.0, TableDiffTask.RunChecks() created a connection pool per node but only closed it on the success path (line 941). Any error before that — missing table, no primary key, schema mismatch, or insufficient privileges — returned without closing the pool. Because pgxpool keeps a background health-check goroutine alive, leaked pools and their connections persisted for the lifetime of the process. In a scheduled repset-diff, the leaks accumulated across runs: if N tables consistently failed RunChecks, each 10-minute tick leaked N more connections. A user with 100 tables saw 79 leaked connections after their ACE user lost table privileges. Wrap the per-node work in a closure so defer conn.Close() scopes to each loop iteration and covers all error paths. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughRefactors per-node connection handling in Changes
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Up to standards ✅🟢 Issues
|
| Category | Results |
|---|---|
| Complexity | 5 medium |
🟢 Metrics 50 complexity · 14 duplication
Metric Results Complexity 50 Duplication 14
TIP This summary will be updated as you push new changes. Give us feedback
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@tests/integration/repset_diff_connleak_test.go`:
- Around line 135-167: The peak-connection assertion is flaky because
monitorConnections (used via monitorPools and pollInterval) only samples on
ticker edges and can miss brief spikes; update the test to ensure peaks can't be
missed by either increasing sampling frequency and/or taking continuous/final
immediate samples: modify the monitorConnections invocation or implementation to
sample more frequently (reduce pollInterval), add an immediate sample before
stopping and another right after diff.RepsetDiff returns, and/or extend
monitorConnections to record instantaneous max from pg_stat_activity on stop;
reference monitorConnections, pollInterval, snapshots, stopMonitor and the
helper in repset_diff_conntrack_test.go to locate and change the sampling
behavior so the peak assertion against maxConnections is reliable.
- Around line 380-387: The test currently ignores the result of
diff.RepsetDiff(task); change the loop to capture and assert that it returns an
error (or a specific error type/message) so the bad-table RunChecks path is
exercised. Specifically, call err := diff.RepsetDiff(task) and add an assertion
(e.g., require.Error/Assert.Error and optionally
require.Contains/Assert.Contains against the expected "missing table" message)
for each invocation created by newTestRepsetDiffTask(repsetName) with
SkipDBUpdate=true and MaxConnections set; this ensures the broken-table failure
path (RunChecks) was actually hit rather than silently discarded.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d7cd68f6-2628-4692-abe9-5bb66a3deef7
📒 Files selected for processing (2)
internal/consistency/diff/table_diff.gotests/integration/repset_diff_connleak_test.go
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
At v1.8.0, TableDiffTask.RunChecks() created a connection pool per node but only closed it on the success path (line 941). Any error before that — missing table, no primary key, schema mismatch, or insufficient privileges — returned without closing the pool. Because pgxpool keeps a background health-check goroutine alive, leaked pools and their connections persisted for the lifetime of the process.
In a scheduled repset-diff, the leaks accumulated across runs: if N tables consistently failed RunChecks, each 10-minute tick leaked N more connections. A user with 100 tables saw 79 leaked connections after their ACE user lost table privileges.
Wrap the per-node work in a closure so defer conn.Close() scopes to each loop iteration and covers all error paths.