Skip to content

test: retry E2E first navigation on ERR_NETWORK_CHANGED - #298

Open
Aaronontheweb wants to merge 1 commit into
devfrom
fix/e2e-network-change-retry
Open

Aaronontheweb wants to merge 1 commit into
devfrom
fix/e2e-network-change-retry

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Member

Deflakes CanDrawWithTouch, which intermittently fails its first navigation with net::ERR_NETWORK_CHANGED.

Root cause

Chromium aborts in-flight requests when it observes a host network-state change. Docker creating/removing container bridge interfaces while Aspire starts resources produces exactly that. This is a browser/transport behavior, not an app error.

Evidence

From run 40782982599, job Test-ubuntu-latest:

[xUnit.net] DrawingTouchInteractionTests.CanDrawWithTouch(viewPortX: 768, viewPortY: 1024) [FAIL]
Microsoft.Playwright.PlaywrightException : net::ERR_NETWORK_CHANGED at http://localhost:34677/
  - navigating to "http://localhost:34677/", waiting until "load"
  • The failing case died in 114 ms versus 1-3 s for the three passing viewports - it aborted before the page rendered anything.
  • Rerunning the failed jobs passed all four viewports.
  • Same signature documented in microsoft/playwright#13062 (container, retry clears it) and Grizzly-Endeavors/residuum#592 (Docker bridge churn named as the cause).
  • Kestrel logged no connection abort server-side. A dedicated Akka.NET/Aspire review found no mechanism in this test configuration - single-node cluster, local-only actor on the /paint path, no management/bootstrap/discovery, no restart policy - that can abort an in-flight request.

Fix

GotoWithNetworkChangeRetryAsync retries only when the exception message contains ERR_NETWORK_CHANGED, up to 3 attempts with 250 ms/500 ms backoff. Every other PlaywrightException propagates unchanged, so real failures stay real. The abort happens before the page has rendered, so retrying that specific navigation is side-effect free.

Applied to the first navigation in both interaction tests - DrawingMouseInteractionTests has the identical unguarded pattern and the same exposure.

Deliberately out of scope

  • The separate 5s locator timeout for a[href='NewPaint'] seen on dev in August (run 33213636917) - a Blazor render race after form submit, not a network change. Two independent timing assumptions.
  • The unguarded _localActorHandle.Tell at Paint.razor:268 - an IActorRef? field, assigned at line 162, no null-guard, while lines 240/246 do use ?.. It logs an NRE on every prerendered /paint/{id} teardown, but it is causally independent of this flake (Kestrel swallows it after the response completes). Tracking separately.

Verification

Build: 0 errors. Full verification is CI-only - Playwright browsers and a warm SQL Server image are not available on this host, and the flake is intermittent (~2 known failures over months), so a green run is necessary but not sufficient signal.

CanDrawWithTouch intermittently fails its very first navigation with
'net::ERR_NETWORK_CHANGED at http://localhost:<port>/'. That is Chromium
aborting an in-flight request because it observed a host network-state
change - Docker creating/removing container bridge interfaces while
Aspire starts resources produces exactly that. It is not an app error.

Evidence (run 40782982599, Test-ubuntu-latest):
- Failed case died in 114ms versus 1-3s for the three passing viewports,
  so it aborted before the page rendered anything.
- Rerunning the failed jobs passed all four viewports.
- Same signature documented in microsoft/playwright#13062 (container,
  retry clears it) and Grizzly-Endeavors/residuum#592 (Docker bridge
  churn explicitly named as the cause).

Fix: add GotoWithNetworkChangeRetryAsync, which retries only when the
exception message contains ERR_NETWORK_CHANGED, up to 3 attempts with
backoff. Any other PlaywrightException propagates unchanged, so real
failures are still real failures. The abort happens before the page has
rendered, so retrying that specific navigation is side-effect free.

Applied to the first navigation in both E2E interaction tests - the
mouse test has the identical unguarded pattern and the same exposure.

Scope is deliberately minimal: this does not address the separate
5s locator timeout for a[href='NewPaint'] seen on dev in August, nor
the unguarded _localActorHandle.Tell in Paint.razor:268.
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