diff --git a/Sources/Amplitude/Utilities/EventPipeline.swift b/Sources/Amplitude/Utilities/EventPipeline.swift index 611931a..c855783 100644 --- a/Sources/Amplitude/Utilities/EventPipeline.swift +++ b/Sources/Amplitude/Utilities/EventPipeline.swift @@ -8,10 +8,14 @@ import Foundation public class EventPipeline { + static let MAX_CONTINOUS_FAILURE_COUNT: Int = 6 + static let MAX_RETRY_INTERVAL: TimeInterval = 60 + var httpClient: HttpClient let storage: Storage? let logger: (any Logger)? let configuration: Configuration + var continuousFailure: Int = 0 @Atomic internal var eventCount: Int = 0 internal var flushTimer: QueueTimer? @@ -101,13 +105,35 @@ public class EventPipeline { eventsString: eventsString ) responseHandler.handle(result: result) - // Don't send the next event file if we're being deallocated - self.uploadsQueue.async { [weak self] in - guard let self = self else { - return - } + + switch result { + case .success: + self.continuousFailure = 0 + case .failure: + self.continuousFailure += 1 + } + + if self.continuousFailure > Self.MAX_CONTINOUS_FAILURE_COUNT { self.currentUpload = nil - self.sendNextEventFile() + self.configuration.offline = true + self.logger?.log(message: "Request failed more than \(Self.MAX_CONTINOUS_FAILURE_COUNT) times, marking offline") + } else { + // Don't send the next event file if we're being deallocated + let nextFileBlock: () -> Void = { [weak self] in + guard let self = self else { + return + } + self.currentUpload = nil + self.sendNextEventFile() + } + + if self.continuousFailure == 0 { + self.uploadsQueue.async(execute: nextFileBlock) + } else { + let sendingInterval = min(Self.MAX_RETRY_INTERVAL, pow(2, Double(self.continuousFailure))) + self.uploadsQueue.asyncAfter(deadline: .now() + sendingInterval, execute: nextFileBlock) + self.logger?.debug(message: "Request failed \(self.continuousFailure) times, send next event file in \(sendingInterval) seconds") + } } } }