From b2b4748f396f908e1d62dfdb5e860f6ff79e1d2c Mon Sep 17 00:00:00 2001 From: patricioxavier8 <116120453+patricioxavier8@users.noreply.github.com> Date: Tue, 9 Jun 2026 22:34:03 -0500 Subject: [PATCH] fix: increase multipart upload timeout and improve error propagation - Increased URLSession request timeout to 90 seconds for multipart uploads. - Updated UploadState and runMultipartUpload to track, extract, and propagate the original URLSession/S3 error inside EnrichedError context instead of throwing a generic UploadNotSuccessful error. --- .../Services/Network/NetworkFacade.swift | 52 +++++++++++++++++-- .../Services/Network/UploadMultipart.swift | 2 + 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Sources/InternxtSwiftCore/Services/Network/NetworkFacade.swift b/Sources/InternxtSwiftCore/Services/Network/NetworkFacade.swift index 4ea96ef..6259e22 100644 --- a/Sources/InternxtSwiftCore/Services/Network/NetworkFacade.swift +++ b/Sources/InternxtSwiftCore/Services/Network/NetworkFacade.swift @@ -262,7 +262,47 @@ public struct NetworkFacade { if await uploadState.isAborted() { operationQueue.cancelAllOperations() - throw UploadError.UploadNotSuccessful + let abortError = await uploadState.getAbortError() + + if let enriched = abortError as? EnrichedError { + throw enriched + } + + let errorCode: ErrorCode + var context: [String: String] = [ + "file_size": String(fileSize) + ] + + var underlyingError: Error = abortError ?? UploadError.UploadNotSuccessful + if let uploadError = abortError as? UploadError { + switch uploadError { + case .PartUploadFailed(let partIndex, let partError): + context["part_index"] = String(partIndex) + underlyingError = partError + default: + break + } + } + + if let urlError = underlyingError as? URLError { + context["url_error_code"] = String(urlError.code.rawValue) + switch urlError.code { + case .timedOut: errorCode = .uploadS3Timeout + case .notConnectedToInternet: errorCode = .networkNoConnection + case .networkConnectionLost: errorCode = .networkConnectionLost + case .cannotConnectToHost: errorCode = .networkCannotConnect + default: errorCode = .uploadS3Failed + } + } else { + errorCode = .uploadS3Failed + } + + throw EnrichedError( + code: errorCode, + step: .uploadMultipartPart, + context: context, + cause: abortError ?? UploadError.UploadNotSuccessful + ) } let fileSHA256digest = hasher.finalize() @@ -306,14 +346,20 @@ public struct NetworkFacade { actor UploadState { var uploadAborted = false + var abortError: Error? - func setAborted() { + func setAborted(error: Error? = nil) { uploadAborted = true + self.abortError = error } func isAborted() -> Bool { return uploadAborted } + + func getAbortError() -> Error? { + return abortError + } } public func downloadFile(bucketId: String, fileId: String, encryptedFileDestination: URL, destinationURL: URL, progressHandler: @escaping ProgressHandler, debug: Bool = false) async throws -> URL { @@ -489,7 +535,7 @@ public struct NetworkFacade { completeOperation() } catch { - await uploadState.setAborted() + await uploadState.setAborted(error: error) completeOperation() } } diff --git a/Sources/InternxtSwiftCore/Services/Network/UploadMultipart.swift b/Sources/InternxtSwiftCore/Services/Network/UploadMultipart.swift index b03cfc8..30400b0 100644 --- a/Sources/InternxtSwiftCore/Services/Network/UploadMultipart.swift +++ b/Sources/InternxtSwiftCore/Services/Network/UploadMultipart.swift @@ -43,6 +43,8 @@ public class UploadMultipart: NSObject { private let reduceBandwidth: Bool private lazy var urlSession: URLSession = { let config = URLSessionConfiguration.default + config.timeoutIntervalForRequest = 90 + config.timeoutIntervalForResource = 3600 if reduceBandwidth { config.httpMaximumConnectionsPerHost = 1 }