Repository navigation
Parallelize citus_check_cluster_node_health across source nodes - #8935
Merged
Volkan Cetin (vlkncetin) merged 2 commits intoOct 20, 2026
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8935 +/- ##
=======================================
Coverage 88.81% 88.82%
=======================================
Files 290 290
Lines 65455 65494 +39
Branches 8255 8261 +6
=======================================
+ Hits 58134 58174 +40
Misses 4937 4937
+ Partials 2384 2383 -1 🚀 New features to boost your workflow:
|
Volkan Cetin (vlkncetin)
requested review from
Emel Şimşek (emelsimsek) and
Onur Tirtir (onurctirtir)
October 20, 2026 10:36
Emel Şimşek (emelsimsek)
approved these changes
Oct 20, 2026
Volkan Cetin (vlkncetin)
deleted the
parallelize-cluster-node-health-check
branch
October 20, 2026 13:16
This was referenced Oct 20, 2026
Volkan Cetin (vlkncetin)
added a commit
that referenced
this pull request
Oct 20, 2026
…#8938) Backports #8935 (fadced9). Applies the merged implementation and regression tests unchanged. --------- Co-authored-by: Volkan Cetin <volkanetin@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
ibrahim halatci (ihalatci)
pushed a commit
that referenced
this pull request
Oct 21, 2026
ibrahim halatci (ihalatci)
pushed a commit
that referenced
this pull request
Oct 21, 2026
…#8939) Backports #8935 to release-14.0. - Parallelizes source connections and connectivity probes across source nodes. - Preserves result ordering and true/false/NULL semantics. - Includes the cancellation-test synchronization correction from the release-13.2 backport (#8938). Production code matches #8935; both changed files match #8938. Co-authored-by: Volkan Cetin <volkanetin@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DESCRIPTION: Parallelizes connectivity checks in citus_check_cluster_node_health
Problem
citus_check_cluster_node_health()checks connectivity between every ordered pairof active readable nodes, including self-pairs. It ran these probes one after another.
On a 33-node cluster that is 1,089 probes, and during cluster initialization this
query took longer than the caller's command timeout:
Change
Only
StoreAllConnectivityChecks()inoperations/health_check.cchanges:StartNodeConnection+FinishConnectionListEstablishment). An unreachable source now costs oneconnection timeout in total instead of one per source.
citus_check_connection_to_node(target)to every source, then wait for allsources with
WaitForAllConnections(..., raiseInterrupts = true)beforereading results and moving on to the next target.
source-major order.
Unchanged behavior:
ActiveReadableNodeList(), sorted, followers included), samecolumns, and all N² pairs, including self-pairs.
ORDER BY.probe in flight per source.
true/false/NULLmean the same as before:NULLwhen the probe could notbe sent to the source, or the source's response was not OK. Failures are still
reported as
WARNINGs with the same text, using the same calls asExecuteOptionalRemoteCommand. Only the order of warnings from different sourcescan now vary.
canceling statement due to user request, through theexisting interrupt handling in
WaitForAllConnections.citus_check_connection_to_nodeisuntouched, so there is no upgrade or mixed-version concern.
Trade-off: inbound connections on target nodes
Probes for the same target now run at the same time, so a target can briefly receive
one probe connection from every source (up to N) instead of about one at a time.
The total number of probe connections per run does not change, only how many are
open at once.
There is no cap. On a node with fewer than about N+1 free
max_connectionsslots, aprobe to it could fail and be reported as
false. With the defaultmax_connections = 100there is plenty of headroom at 33 nodes. The benchmark belowmeasures the peak.
Benchmark
Setup: a 33-node cluster (coordinator + 32 workers) on one 16-core host, PostgreSQL
18.6 built with
--enable-cassert, all nodes healthy. Every run returned 1,089 rows,all
true. Each version had one warm-up run, then 5 timed runs of the query above.Peak inbound connections per node come from
log_connections/log_disconnectionsover 3 runs.
All 33 nodes shared one machine and assertions were enabled, so CPU contention
limits the speedup. On real multi-host clusters, where network round-trips dominate,
the gain should be larger. This was not measured.
Unresponsive targets (from the new pytest; 3 healthy nodes plus 3 fake nodes that
accept TCP connections but never respond;
citus.node_connection_timeout = 1sonevery node):
Tests
New
src/test/regress/citus_tests/test/test_cluster_node_health.py:test_cluster_node_health_checks_sources_concurrentlyrolled back.
citus.node_connection_timeoutis set on every node, because eachprobe's timeout is decided on its source node.
ORDER BY: real→real istrue, real→fake isfalse, fake source isNULL.one, and that each fake target saw exactly one probe connection from every real
source at the same time.
rows) and passes with this change (~4 s).
test_cluster_node_health_cancellation_stops_remote_checkswhile every source has a probe to a fake node in flight.
QueryCanceled, and that every source nodelogs
canceling statement due to user requestfor its probe. This shows theremote probes are actually cancelled, not just orphaned by the closed socket.
the fake node are closed within about 0.06 s, far below the 120 s timeout.
The existing regression tests passed with unchanged expected output, including the
mitmproxy kill/cancel/
after(1)cases infailure_connection_establishment.Validation
Run locally against PostgreSQL 18.6 (
--enable-cassert), fromsrc/test/regress:make check-custom-schedule SCHEDULE=<minimal_cluster_management, multi_test_helpers, multi_test_helpers_superuser, connectivity_checks> WORKERCOUNT=2python citus_tests/run_test.py multi_citus_toolspython citus_tests/run_test.py multi_mx_add_coordinatorpython citus_tests/run_test.py failure_connection_establishmentmake check-follower-cluster(includesmulti_follower_select_statements)pytest citus_tests/test/test_cluster_node_health.pypytest citus_tests/test/test_cluster_node_health.py::test_cluster_node_health_checks_sources_concurrentlyagainst the pre-change buildpytest -n autouncrustify -c citus-style.cfg --checkonhealth_check.c(uncrustify 0.82.0, citus_indent v0.8.33)black --check,isort --check,flake8on the new test fileNot run locally: PostgreSQL 17 and 19, and the full
check-multi/check-failureschedules. CI covers these.