Fix flaky test_async_load_databases::test_materialized_views_replicated - #107119
Conversation
The test stops node1, restarts it in a worker thread, and meanwhile issues INSERTs. Two timing assumptions break on slow (sanitizer) builds: 1. `disconnect_event.wait(90)` ignored its return value. When the restart took longer than 90s (plausible under TSan/ASan, where restart's stop+start can approach its 120s budget and startup is much slower), the main thread fell through while the server was still restarting. 2. The INSERT loops used `node1.query(...)` with no per-query timeout. When a query hits a half-restarted server (TCP port open but not yet serving), the clickhouse-client connects and then blocks waiting for a response. With the default DEFAULT_QUERY_TIMEOUT=600s, a single such query can exhaust pytest's 900s per-test timeout, which kills the whole session and also fails the sibling test_materialized_views_cascaded_multiple sharing the module fixture. Fix (test-only, behavior preserved): - assert on `disconnect_event.wait(180)` so a too-slow restart fails loudly with a clear message instead of silently racing ahead; 180s gives sanitizer builds headroom over the original 90s. - pass `timeout=60` to the INSERTs in both loops so a connection to a not-yet-ready server fails fast and attributably instead of hanging up to 600s. - the pre-restart guarded loop now also catches QueryTimeoutExceedException (the new fast-fail path) alongside QueryRuntimeException. The assertions the test makes (row-count propagation through the MV) are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pre-PR validation gate
Note: a separate Session id: cron:clickhouse-worker-slot-30:20260610-235700 |
|
cc @tavplubix could you review this? It fixes the flaky |
|
Workflow [PR], commit [e5479ff] Summary: ✅ AI ReviewSummaryThis PR is a test-only reliability fix for Missing context / blind spots
Final VerdictStatus: ✅ Approve |
Addresses review feedback on PR ClickHouse#107119: the per-query timeout=60 bounds each node1.query but not the loop. In the half-restarted state, all 30 attempts can each block for the full timeout, get swallowed by the except, and accumulate up to ~30 minutes before reaching disconnect_event.wait(180), still overrunning the 900s pytest session timeout. Bound the whole pre-start insert phase: break as soon as the restart finishes (disconnect_event.is_set()) or a 180s phase deadline (the restart budget) elapses. Worst case is now ~240s (180s deadline + one in-flight 60s query), well under the 900s session timeout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LLVM Coverage Report
Changed lines: No C/C++ source files changed — skipping uncovered code analysis. Newly covered by added/modified tests: 371 line(s), 22 function(s) across 148 file(s) · Details Top files
|
|
CI finished for HEAD |
Backport #107119 to 25.8: Fix flaky test_async_load_databases::test_materialized_views_replicated
Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
...
Description
Fixes flaky
test_async_load_databases::test_materialized_views_replicated. 13 distinct PR groups hit it in the last 30 days (most recent 2026-06-10); the dominant signature is an emptytest_context_raw(the 900s pytest session timeout), and when the session is killed it takes the siblingtest_materialized_views_cascaded_multipledown too (shared module fixture).Root cause (two cooperating timing assumptions that break on slow sanitizer builds):
disconnect_event.wait(90)ignored its return value. Whenrestart_clickhouse()takes longer than 90s (its stop+start budget alone is ~120s, and startup is much slower under TSan/ASan), the main thread fell through while the server was still restarting.node1.query(...)with no per-query timeout. A query to a half-restarted server (TCP port open but not yet serving) makesclickhouse-clientconnect and then block on the response. WithDEFAULT_QUERY_TIMEOUT=600s, one such query exhausts the 900s session timeout.Fix (test-only, assertions unchanged):
assert disconnect_event.wait(180)so a too-slow restart fails loudly instead of silently racing ahead (180s gives sanitizer builds headroom over the original 90s).timeout=60on the INSERTs in both loops, so a connection to a not-yet-ready server fails fast and attributably instead of hanging up to 600s.QueryTimeoutExceedException(the new fast-fail path).Reproduced and validated locally (native integration runner, debug build): unmodified test passes on a fast build (race doesn't trigger); with an injected slow restart, an unguarded
query(timeout=None)against a half-up server blocks indefinitely whiletimeout=60fails in seconds; the fixed test passes 3/3 repeated runs.Version info
26.6.1.955(included in26.6and later)25.8.26.9