Skip to content

Custom view panels say a silent store's open timed out, whatever the driver wraps the timeout in, and the open-timeout test names the exception chain when it fails - #5052

Merged
erikdarlingdata merged 3 commits into
devfrom
fix/silent-store-open-timeout
Oct 3, 2026
Merged

erikdarlingdata merged 3 commits into
devfrom
fix/silent-store-open-timeout

Conversation

@erikdarlingdata

@erikdarlingdata erikdarlingdata commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

What changes

CI has twice failed ComposeOpenPhaseTimeoutTests.ASilentStore_IsAServerError_NotTheStatementTimeoutText(remapClientTimeout: True) on unrelated PRs, because a silent store sometimes answered "could not open a store connection: Exception while reading from stream" instead of "could not get a store connection in time". #5016 says this shape was never reproduced locally, so this PR does two things that do not depend on knowing the shape.

  1. The failure names its cause. RunComposedPanelAsync takes an optional onRunException callback (a test seam on the generic-exception arm, internal and unused by production callers). ComposeOpenPhaseTimeoutTests captures the exception and appends each level's type and message, plus SocketException.SocketErrorCode and IOException.HResult, to the prefix assert's message.
  2. The clock decides. OpenComposeConnectionAsync times the open. When it fails with an NpgsqlException after at least the data source's connection Timeout (minus 100 ms slack), the answer is "in time". This is an OR beside PostgresOpenTimeout.IsTimedOutOpen, whose shape rules are unchanged. A PostgresException or OperationCanceledException anywhere in the chain, a cancelled caller token, or a failure well before the timeout (refused, reset, closed, auth) still says "could not open". The rule lives in PostgresOpenTimeout.IsTimedOutByClock, a pure function. This covers both the web route and run_custom_view_panel, which share the runner.

Test plan

  • New in PostgresOpenTimeoutTests (no sockets, no sleeps): aborted-socket read at/near Timeout is timed out; at 50 ms is not; PostgresException at Timeout is not; caller cancellation at Timeout is not; an NpgsqlException over a nested OperationCanceledException with the caller live is timed out; the wrapper's flag drives the sentence.
  • Revert-proof: the new IsTimedOutByClock/FailedAfterTimeout tests do not compile on dev. AnAbortedSocketRead_IsNotATimeoutByShape is a gap pin (it asserts false, so it passes on dev; it is not a runtime RED). The wrapper pin TheOpenHelper_ClocksTheOpen_AndFlagsALateFailure_AndTheSentenceReadsTheFlag is RED when any one of Stopwatch.StartNew(), the IsTimedOutByClock( call, { FailedAfterTimeout = true } or || open.FailedAfterTimeout is deleted (each tried, each failed).
  • Ran here (macOS) after round 1: PostgresOpenTimeoutTests 23/0; ComposeClientTimeoutAttributionTests 19/0; ComposeOpenPhaseTimeoutTests 3/0; WebExceptionTextCensusTests 40/0 (1 skip, live); DarlingComposeTests 305/0.
  • Only CI proves the original flake is gone, since it is Windows-only and unreproduced locally. If it recurs, the assert message now prints the chain.

Follow-up to #5016

Round 1 fixes

  1. Dropped the nested-OperationCanceledException exclusion from IsTimedOutByClock. A caller's cancellation is caught upstream and callerCancelled covers it, so a nested one with a live caller is the driver's own Timeout timer. The doc comment says so; new test added, and the cancelled-caller test kept.
  2. Added the source pin for the wrapper (see Test plan).
  3. Reworded the RED claim (see Test plan).
  4. Timeout is now read before the open, outside the catch, with an ArgumentException guard that turns the clock rule off.

CHANGELOG entry

SECTION: Fixed
ENTRY: A custom view panel whose store accepts the connection but never answers now reports that the connection timed out, on the web route and in run_custom_view_panel, instead of "could not open a store connection". (Folds into the #5016 entry.)

erikdarlingdata and others added 3 commits October 3, 2026 17:14
…t in; name the exception chain when the open-timeout test fails (follow-up to #5016)
Drop the nested OperationCanceledException exclusion from IsTimedOutByClock
(the caller's cancellation is already covered by callerCancelled, and a nested
one with a live caller is the driver's own Timeout timer). Pin the open helper's
stopwatch, clock call, flag and the FromRunException read with a source test.
Read the data source Timeout before the open, outside the catch.
@erikdarlingdata
erikdarlingdata marked this pull request as ready for review October 3, 2026 22:17
@erikdarlingdata
erikdarlingdata merged commit f02867d into dev Oct 3, 2026
21 of 22 checks passed
@erikdarlingdata
erikdarlingdata deleted the fix/silent-store-open-timeout branch October 3, 2026 22:24
erikdarlingdata added a commit that referenced this pull request Oct 3, 2026
…2013 (#5052) (#5054)

#5052's source pin counted one match with Assert.Equal(1, ....Count), which the xUnit2013 analyzer warns on, so dev built Darling.Tests with 1 warning again. It now uses Assert.Single, with the same assertion: exactly one FailedAfterTimeout = true in the compose open helper. Dev builds with 0 warnings again.

Follow-up to #5052
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.

1 participant