#69364·aspnetcore

Retry transient network failures when bootstrapping the SignalR Java Gradle distribution

Author: mmitcheCreated Sep 17, 2026Updated Sep 17, 2026
Labelstest-failurearea-infrastructure

Problem

SignalR Java builds can fail during Gradle distribution bootstrap on transient DNS/network errors. The checked-in Gradle 9.2.1 wrapper does not retry hostname-resolution failures, so one failed lookup aborts the Java build with MSBuild error MSB3073.

This issue concerns Gradle bootstrap only. Independent Blazor test and Windows test-log file-lock failures in the same pipeline are out of scope.

Evidence

Pipeline: aspnetcore-ci (83), build 1597302, branch refs/pull/67492/merge, associated with dotnet/aspnetcore#67492.

Executed merge commit: bee4e13f67ce8bc47fa19233dc51b3f591794e0d.

The initial Test: macOS job (job attempt 1, Run build.sh task attempt 1) failed on September 15, 2026.

Failed step · Exact failure log

L1239: 2026-09-15T10:37:48.6364680Z   Downloading https://services.gradle.org/distributions/gradle-9.2.1-bin.zip
L1241: 2026-09-15T10:38:20.4837890Z   Exception in thread "main" java.net.UnknownHostException: services.gradle.org
L1264: 2026-09-15T10:38:22.7538790Z ##[error]eng/targets/Java.Common.targets(59,5): error MSB3073: The command "../gradlew  -Dorg.gradle.daemon=false --stacktrace --console=plain compileJava" exited with code 1.

The same build's macOS job attempt 2 downloaded the same distribution and compiled Java successfully at the same source commit, on a different agent with the same macOS image version (20260824.0482.1).

Exact recovery log

L1239: 2026-09-15T12:33:17.2718480Z   Downloading https://services.gradle.org/distributions/gradle-9.2.1-bin.zip
L1242: 2026-09-15T12:33:37.3875450Z   Welcome to Gradle 9.2.1!
L1295: 2026-09-15T12:35:12.5305460Z   > Task :core:compileJava
L1309: 2026-09-15T12:35:22.3667290Z   BUILD SUCCESSFUL in 2m 4s

Same-commit checkout evidence: initial checkout and recovery checkout.

This strongly supports a transient or agent-specific infrastructure failure. It does not identify whether the faulty layer was the agent resolver, proxy/network path, or upstream DNS.

Implementation context

The Gradle-provided wrapper is checked into src/SignalR/clients/java/signalr/: gradlew, gradlew.bat, gradle/wrapper/gradle-wrapper.jar, and gradle/wrapper/gradle-wrapper.properties.

Proposed solution

Add bounded backoff retries specifically for Gradle distribution bootstrap, before Java compilation. Prefer an existing repository bootstrap/download helper if suitable. A repository-side bootstrap helper is one option; adopting an upstream wrapper enhancement is another if it demonstrably covers DNS failures. Do not hand-edit or fork the generated wrapper JAR.

Suggested policy: three total acquisition attempts with short delays, such as 2 seconds then 5 seconds. These values are a proposal, not existing behavior.

Requirements:

  • Retry only classified transient acquisition failures: hostname resolution, connection reset/timeout, and selected transient HTTP responses.
  • Do not retry arbitrary gradlew failures, Java compilation, tests, or the full Run build.sh step.
  • Use the configured distribution URL/version/checksum rather than introducing a second hard-coded configuration.
  • Preserve mandatory SHA-256 verification. Checksum mismatches and non-transient errors must fail explicitly; never execute an unvalidated or partial distribution.
  • Preserve wrapper cache behavior and safe concurrent acquisition. Avoid unnecessary downloads on valid cache hits and competing unsafe cache writers.
  • Log the endpoint, attempt count, reason, and backoff; retain a clear terminal error after the final attempt. Do not log credentials.
  • Keep behavior consistent across supported launch paths, particularly macOS.

A trusted mirror or checksum-validated pipeline cache could additionally reduce external dependency exposure, but cache misses still require correct failure handling.

Acceptance criteria

  • With an empty cache, an injected transient DNS failure followed by recovery succeeds within the bounded acquisition attempts; compilation then runs once.
  • Persistent DNS/network failure exhausts the attempts and fails clearly with retry history.
  • Checksum mismatches and non-transient failures are not masked or retried as ordinary transient network errors.
  • Valid cache hits avoid acquisition.
  • Interrupted downloads and concurrent bootstrap cannot produce an accepted corrupt distribution.
  • Genuine Java compilation/test failures propagate without retries.
  • Existing successful SignalR Java build behavior remains intact.

No implementation or CI reruns were performed during the investigation.