@@ -297,7 +297,7 @@ public struct RetryRequestCondition {
297297 if case let . success( response) = response {
298298 return codes. contains ( response. status)
299299 }
300- return true
300+ return false
301301 }
302302 }
303303}
@@ -339,7 +339,9 @@ private struct retryMiddleware: HTTPClientMiddleware {
339339 let interval = configs. retryInterval
340340 let backoffPolicy = configs. retryBackoffPolicy
341341 if let hash = backoffPolicy. scopeHash ( request) {
342- await waitForSynchronizedAccess ( id: hash, of: Void . self)
342+ if let interval = await waitForSynchronizedAccess ( id: hash, of: UInt64 . self) {
343+ try await Task . sleep ( nanoseconds: jitterNs ( interval) )
344+ }
343345 }
344346 var count = 0
345347 var resp : HTTPResponse ?
@@ -350,7 +352,7 @@ private struct retryMiddleware: HTTPClientMiddleware {
350352 return false
351353 }
352354 if let limit {
353- return count <= limit
355+ return count < limit
354356 }
355357 return true
356358 }
@@ -360,8 +362,9 @@ private struct retryMiddleware: HTTPClientMiddleware {
360362 let interval = UInt64 ( max ( retryAfterHeader, interval ( count - 1 ) ) * 1_000_000_000 )
361363 if interval > 0 {
362364 if let resp, let hash = backoffPolicy. scopeHash ( request) , backoffPolicy. isGlobalBackoff ( request, resp) {
363- try await withThrowingSynchronizedAccess ( id: hash) {
365+ _ = try await withThrowingSynchronizedAccess ( id: hash) {
364366 try await Task . sleep ( nanoseconds: interval)
367+ return interval
365368 }
366369 } else {
367370 try await Task . sleep ( nanoseconds: interval)
@@ -377,9 +380,11 @@ private struct retryMiddleware: HTTPClientMiddleware {
377380 do {
378381 let ( data, response) = try await retry ( )
379382 resp = response
380- retryAfterHeader = response. headerFields [ . retryAfter] . flatMap {
381- decodeRetryAfterHeader ( $0, formatter: configs. retryAfterHeaderDateFormatter)
382- } ?? 0
383+ if [ 429 , 503 ] . contains ( response. status. code) {
384+ retryAfterHeader = response. headerFields [ . retryAfter] . flatMap {
385+ decodeRetryAfterHeader ( $0, formatter: configs. retryAfterHeaderDateFormatter)
386+ } ?? 0
387+ }
383388 if !needRetry( . success( response) ) {
384389 return ( data, response)
385390 }
@@ -393,6 +398,20 @@ private struct retryMiddleware: HTTPClientMiddleware {
393398 }
394399}
395400
401+ @inline ( __always)
402+ private func jitterNs(
403+ _ base: UInt64 ,
404+ fraction: ClosedRange < Double > = 0.1 ... 0.2 ,
405+ minNs: UInt64 = 5_000_000 , // 5 ms
406+ maxNs: UInt64 = 1_000_000_000
407+ ) // 1 s
408+ -> UInt64 {
409+ guard base > 0 else { return 0 }
410+ let p = Double . random ( in: fraction)
411+ let raw = UInt64 ( Double ( base) * p)
412+ return min ( max ( raw, minNs) , maxNs)
413+ }
414+
396415private func decodeRetryAfterHeader( _ value: String , formatter: DateFormatter ) -> TimeInterval ? {
397416 // seconds
398417 if let seconds = TimeInterval ( value) {
0 commit comments