| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- /*
- * Copyright 2024, gRPC Authors All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
- struct ConnectionBackoff {
- var initial: Duration
- var max: Duration
- var multiplier: Double
- var jitter: Double
- init(initial: Duration, max: Duration, multiplier: Double, jitter: Double) {
- self.initial = initial
- self.max = max
- self.multiplier = multiplier
- self.jitter = jitter
- }
- func makeIterator() -> Iterator {
- return Iterator(self)
- }
- // Deliberately not conforming to `IteratorProtocol` as `next()` never returns `nil` which
- // isn't expressible via `IteratorProtocol`.
- struct Iterator {
- private var isInitial: Bool
- private var currentBackoffSeconds: Double
- private let jitter: Double
- private let multiplier: Double
- private let maxBackoffSeconds: Double
- init(_ backoff: ConnectionBackoff) {
- self.isInitial = true
- self.currentBackoffSeconds = Self.seconds(from: backoff.initial)
- self.jitter = backoff.jitter
- self.multiplier = backoff.multiplier
- self.maxBackoffSeconds = Self.seconds(from: backoff.max)
- }
- private static func seconds(from duration: Duration) -> Double {
- var seconds = Double(duration.components.seconds)
- seconds += Double(duration.components.attoseconds) / 1e18
- return seconds
- }
- private static func duration(from seconds: Double) -> Duration {
- let nanoseconds = seconds * 1e9
- let wholeNanos = Int64(nanoseconds)
- return .nanoseconds(wholeNanos)
- }
- mutating func next() -> Duration {
- // The initial backoff doesn't get jittered.
- if self.isInitial {
- self.isInitial = false
- return Self.duration(from: self.currentBackoffSeconds)
- }
- // Scale up the last backoff.
- self.currentBackoffSeconds *= self.multiplier
- // Limit it to the max backoff.
- if self.currentBackoffSeconds > self.maxBackoffSeconds {
- self.currentBackoffSeconds = self.maxBackoffSeconds
- }
- let backoff = self.currentBackoffSeconds
- let jitter = Double.random(in: -(self.jitter * backoff) ... self.jitter * backoff)
- let jitteredBackoff = backoff + jitter
- return Self.duration(from: jitteredBackoff)
- }
- }
- }
|