From 32d62e9898ffa57c6c5cce9be212a688bb85061d Mon Sep 17 00:00:00 2001 From: Bassam Khouri Date: Thu, 20 Aug 2026 22:36:36 -0400 Subject: [PATCH] Increase PR url download retry GitHub actions would sometimes fails with the following ``` Failed to load PR info from https://api.github.com/repos/swiftlang/swift-build/pulls/1657 (attempt 1 of 5): DecodingError.keyNotFound: Key 'base' not found in keyed decoding container. Debug description: No value associated with key CodingKeys(stringValue: "base", intValue: nil) ("base").. Retrying in 1s... Failed to load PR info from https://api.github.com/repos/swiftlang/swift-build/pulls/1657 (attempt 2 of 5): DecodingError.keyNotFound: Key 'base' not found in keyed decoding container. Debug description: No value associated with key CodingKeys(stringValue: "base", intValue: nil) ("base").. Retrying in 2s... Failed to load PR info from https://api.github.com/repos/swiftlang/swift-build/pulls/1657 (attempt 3 of 5): DecodingError.keyNotFound: Key 'base' not found in keyed decoding container. Debug description: No value associated with key CodingKeys(stringValue: "base", intValue: nil) ("base").. Retrying in 4s... Failed to load PR info from https://api.github.com/repos/swiftlang/swift-build/pulls/1657 (attempt 4 of 5): DecodingError.keyNotFound: Key 'base' not found in keyed decoding container. Debug description: No value associated with key CodingKeys(stringValue: "base", intValue: nil) ("base").. Retrying in 8s... Failed to load PR info from https://api.github.com/repos/swiftlang/swift-build/pulls/1657 after 5 attempts: DecodingError.keyNotFound: Key 'base' not found in keyed decoding container. Debug description: No value associated with key CodingKeys(stringValue: "base", intValue: nil) ("base"). ``` Although there was a retry mechanism, it was not sufficient in some cases. Update the retry time from [1, 2, 4, 8] seconds across the 4 retries (total ~15s). to [5, 10, 20, 40] seconds across the 4 retries (total ~75s) --- .github/workflows/scripts/cross-pr-checkout.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scripts/cross-pr-checkout.swift b/.github/workflows/scripts/cross-pr-checkout.swift index 5bce0c12..9553f687 100644 --- a/.github/workflows/scripts/cross-pr-checkout.swift +++ b/.github/workflows/scripts/cross-pr-checkout.swift @@ -81,6 +81,7 @@ public func lookup(executable: String) throws -> URL { } func downloadData(from url: URL) async throws -> Data { + print("Retrieving data from \(url)...") return try await withCheckedThrowingContinuation { continuation in URLSession.shared.dataTask(with: url) { data, _, error in if let error { @@ -124,12 +125,13 @@ func getPRInfo(repository: String, prNumber: String) async throws -> PRInfo { let data = try await downloadData(from: prInfoUrl) return try JSONDecoder().decode(PRInfo.self, from: data) } catch { + let messagePrefix = "[\(attempt) / \(maxAttempts)] Failed to load PR info from \(prInfoUrl)" if attempt == maxAttempts { - throw GenericError("Failed to load PR info from \(prInfoUrl) after \(maxAttempts) attempts: \(error)") + throw GenericError("\(messagePrefix) after \(maxAttempts) attempts: \(error)") } - let delaySeconds = UInt64(1 << (attempt - 1)) + let delaySeconds = UInt64(5 << (attempt - 1)) print( - "Failed to load PR info from \(prInfoUrl) (attempt \(attempt) of \(maxAttempts)): \(error). Retrying in \(delaySeconds)s..." + "\(messagePrefix) with error\n\n\(error)\n\nRetrying in \(delaySeconds) seconds..." ) try await Task.sleep(for: .seconds(delaySeconds)) attempt += 1