Skip to content

Retry net48 UsageFixture tests on transport read timeouts - #731

Draft
todthomson wants to merge 1 commit into
mainfrom
todthomson/lev-2253-halibut-net48-transport-read-timeouts-intermittently-block
Draft

todthomson wants to merge 1 commit into
mainfrom
todthomson/lev-2253-halibut-net48-transport-read-timeouts-intermittently-block

Conversation

@todthomson

Copy link
Copy Markdown
Member

Background

Since mid-October the Halibut nightly chain (Full Chain and Nightly) has been reported as "failed to start" every few days. Each time, one UsageFixture test on net48 has failed with a transport read timeout: HalibutClientException → IOException → SocketException, under MessageExchangeStream.ReceiveResponseAsync / RewindableBufferStream.ReadAsync. That fails the test build, which blocks CreateRelease, so the chain never starts.

The failures were filed per test variant (LEV-2173, LEV-2244, LEV-2245, LEV-2246) and are now consolidated in LEV-2253. The root cause is still being investigated. This PR only stops a single timeout from blocking the whole nightly.

Results

  • New [RetryOnTransportTimeout] NUnit attribute. It retries a test only when it fails with a transport timeout: a SocketException with SocketError.TimedOut anywhere in the exception chain, the net48 "did not properly respond after a period of time" message, or "polling endpoint did not collect the request within the allowed time". Assertion failures, protocol errors, connection refused and anything else fail immediately. NUnit's built-in [Retry] can't be used because it only retries assertion failures.
  • Scope. 3 attempts in total, and only on .NET Framework by default (#if NETFRAMEWORK). On net10 tests run once, exactly as before.
  • Retries stay visible. Each retry writes a line naming LEV-2253 to the test output. Under TeamCity it also emits a WARNING message and ##teamcity[addBuildTag 'halibut-transport-timeout-retry'], so affected builds can be counted.
  • Applied to the four UsageFixture tests behind the duplicate issues: OctopusCanSendMessagesToTentacle_WithEchoService, OctopusCanSendMessagesToTentacle_WithSupportedServices, StreamsCanBeSent and LargeMessages.
  • Supporting changes, needed because a retry re-runs SetUp. SerilogLoggerBuilder no longer throws "test is being run multiple times" when CurrentRepeatCount > 0. TraceLogFileLogger appends instead of deleting on a retry, so the failed attempt's trace log is kept.

Refs LEV-2253

How to review this PR

Quality ✔️

  • Review the retry command in RetryOnTransportTimeoutAttribute. It uses one Wrap for both IWrapTestMethod (captures the exception) and IRepeatTest (the retry loop), and tells them apart by whether the command is a TestMethodCommand.
  • Check the TransportTimeoutClassifier matches are narrow enough.

Testing done: on net10 (Linux), the new TransportTimeoutClassifierFixture and RetryOnTransportTimeoutAttributeFixture tests pass, along with all of UsageFixture (108 tests in the filter, all passing). The retry fixture confirms a test that times out once passes on retry and that SetUp runs again on each attempt.

Not yet verified: the net48 build (no .NET Framework reference assemblies were available where this was written), and whether the ##teamcity service messages are picked up through dotnet test. CI on this PR will show both.

Pre-requisites

  • I have read How we use GitHub Issues for help deciding when and where it's appropriate to make an issue.
  • I have considered informing or consulting the right people, according to the ownership map.
  • I have considered appropriate testing for my change.

Generated by Claude Code

Adds a RetryOnTransportTimeout test attribute. It retries a test only when
the test fails with a transport read timeout (socket TimedOut, or a polling
request not collected in time); every other failure fails immediately.
Retries apply on .NET Framework only by default. Each retry is reported in
the test output and, under TeamCity, as a warning plus the
'halibut-transport-timeout-retry' build tag, so the cause stays visible.

A retried test keeps its earlier attempt's trace log and is allowed to
replace its trace logger.

The attribute is applied to the UsageFixture tests whose net48 timeouts have
been blocking the nightly Full Chain (LEV-2173, LEV-2244, LEV-2245,
LEV-2246). Tests cover the classifier and the retry behaviour.

Refs LEV-2253

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012CQ12HPMmHGEcvKjdG43mj
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