Skip to content

Commit a5ff83c

Browse files
authored
correct decorrelated algorithm
1 parent 09538a5 commit a5ff83c

File tree

1 file changed

+20
-27
lines changed

1 file changed

+20
-27
lines changed

Sources/AsyncAlgorithms/Retry/Backoff.swift

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ public protocol BackoffStrategy<Duration> {
1717
}
1818

1919
@available(iOS 16.0, macCatalyst 16.0, macOS 13.0, tvOS 16.0, visionOS 1.0, watchOS 9.0, *)
20-
@usableFromInline
21-
struct ConstantBackoffStrategy<Duration: DurationProtocol>: BackoffStrategy {
20+
@usableFromInline struct ConstantBackoffStrategy<Duration: DurationProtocol>: BackoffStrategy {
2221
@usableFromInline let constant: Duration
2322
@usableFromInline init(constant: Duration) {
24-
precondition(constant >= .zero, "Constsnt must be greater than or equal to 0")
23+
precondition(constant >= .zero, "Constant must be greater than or equal to 0")
2524
self.constant = constant
2625
}
2726
@inlinable func nextDuration() -> Duration {
@@ -30,8 +29,7 @@ struct ConstantBackoffStrategy<Duration: DurationProtocol>: BackoffStrategy {
3029
}
3130

3231
@available(iOS 16.0, macCatalyst 16.0, macOS 13.0, tvOS 16.0, visionOS 1.0, watchOS 9.0, *)
33-
@usableFromInline
34-
struct LinearBackoffStrategy<Duration: DurationProtocol>: BackoffStrategy {
32+
@usableFromInline struct LinearBackoffStrategy<Duration: DurationProtocol>: BackoffStrategy {
3533
@usableFromInline var current: Duration
3634
@usableFromInline let increment: Duration
3735
@usableFromInline init(increment: Duration, initial: Duration) {
@@ -63,8 +61,7 @@ struct LinearBackoffStrategy<Duration: DurationProtocol>: BackoffStrategy {
6361
}
6462

6563
@available(iOS 16.0, macCatalyst 16.0, macOS 13.0, tvOS 16.0, visionOS 1.0, watchOS 9.0, *)
66-
@usableFromInline
67-
struct MinimumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
64+
@usableFromInline struct MinimumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
6865
@usableFromInline var base: Base
6966
@usableFromInline let minimum: Base.Duration
7067
@usableFromInline init(base: Base, minimum: Base.Duration) {
@@ -77,8 +74,7 @@ struct MinimumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
7774
}
7875

7976
@available(iOS 16.0, macCatalyst 16.0, macOS 13.0, tvOS 16.0, visionOS 1.0, watchOS 9.0, *)
80-
@usableFromInline
81-
struct MaximumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
77+
@usableFromInline struct MaximumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
8278
@usableFromInline var base: Base
8379
@usableFromInline let maximum: Base.Duration
8480
@usableFromInline init(base: Base, maximum: Base.Duration) {
@@ -91,22 +87,20 @@ struct MaximumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
9187
}
9288

9389
@available(iOS 18.0, macCatalyst 18.0, macOS 15.0, tvOS 18.0, visionOS 2.0, watchOS 11.0, *)
94-
@usableFromInline
95-
struct FullJitterBackoffStrategy<Base: BackoffStrategy, RNG: RandomNumberGenerator>: BackoffStrategy where Base.Duration == Swift.Duration {
90+
@usableFromInline struct FullJitterBackoffStrategy<Base: BackoffStrategy, RNG: RandomNumberGenerator>: BackoffStrategy where Base.Duration == Swift.Duration {
9691
@usableFromInline var base: Base
9792
@usableFromInline var generator: RNG
9893
@usableFromInline init(base: Base, generator: RNG) {
9994
self.base = base
10095
self.generator = generator
10196
}
10297
@inlinable mutating func nextDuration() -> Base.Duration {
103-
return .init(attoseconds: Int128.random(in: 0...base.nextDuration().attoseconds))
98+
return .init(attoseconds: Int128.random(in: 0...base.nextDuration().attoseconds, using: &generator))
10499
}
105100
}
106101

107102
@available(iOS 18.0, macCatalyst 18.0, macOS 15.0, tvOS 18.0, visionOS 2.0, watchOS 11.0, *)
108-
@usableFromInline
109-
struct EqualJitterBackoffStrategy<Base: BackoffStrategy, RNG: RandomNumberGenerator>: BackoffStrategy where Base.Duration == Swift.Duration {
103+
@usableFromInline struct EqualJitterBackoffStrategy<Base: BackoffStrategy, RNG: RandomNumberGenerator>: BackoffStrategy where Base.Duration == Swift.Duration {
110104
@usableFromInline var base: Base
111105
@usableFromInline var generator: RNG
112106
@usableFromInline init(base: Base, generator: RNG) {
@@ -120,23 +114,22 @@ struct EqualJitterBackoffStrategy<Base: BackoffStrategy, RNG: RandomNumberGenera
120114
}
121115

122116
@available(iOS 18.0, macCatalyst 18.0, macOS 15.0, tvOS 18.0, visionOS 2.0, watchOS 11.0, *)
123-
@usableFromInline
124-
struct DecorrelatedJitterBackoffStrategy<Base: BackoffStrategy, RNG: RandomNumberGenerator>: BackoffStrategy where Base.Duration == Swift.Duration {
125-
@usableFromInline var base: Base
117+
@usableFromInline struct DecorrelatedJitterBackoffStrategy<RNG: RandomNumberGenerator>: BackoffStrategy {
118+
@usableFromInline let base: Duration
119+
@usableFromInline let factor: Int
126120
@usableFromInline var generator: RNG
127121
@usableFromInline var current: Duration?
128-
@usableFromInline let factor: Int
129-
@usableFromInline init(base: Base, generator: RNG, factor: Int) {
122+
@usableFromInline init(base: Duration, factor: Int, generator: RNG) {
130123
precondition(factor >= 1, "Factor must be greater than or equal to 1")
124+
precondition(base >= .zero, "Base must be greater than or equal to 0")
131125
self.base = base
132126
self.generator = generator
133127
self.factor = factor
134128
}
135-
@inlinable mutating func nextDuration() -> Base.Duration {
136-
let base = base.nextDuration()
137-
let current = current ?? base
138-
let next = Duration(attoseconds: Int128.random(in: base.attoseconds...(current * factor).attoseconds, using: &generator))
139-
self.current = next
129+
@inlinable mutating func nextDuration() -> Duration {
130+
let previous = current ?? base
131+
let next = Duration(attoseconds: Int128.random(in: base.attoseconds...(previous * factor).attoseconds, using: &generator))
132+
current = next
140133
return next
141134
}
142135
}
@@ -161,6 +154,9 @@ public enum Backoff {
161154
@inlinable public static func exponential(factor: Int, initial: Duration) -> some BackoffStrategy<Duration> {
162155
return ExponentialBackoffStrategy(factor: factor, initial: initial)
163156
}
157+
@inlinable public static func decorrelatedJitter<RNG: RandomNumberGenerator>(factor: Int, base: Duration, using generator: RNG) -> some BackoffStrategy<Duration> {
158+
return DecorrelatedJitterBackoffStrategy(base: base, factor: factor, generator: generator)
159+
}
164160
}
165161

166162
@available(iOS 16.0, macCatalyst 16.0, macOS 13.0, tvOS 16.0, visionOS 1.0, watchOS 9.0, *)
@@ -181,7 +177,4 @@ extension BackoffStrategy where Duration == Swift.Duration {
181177
@inlinable public func equalJitter<RNG: RandomNumberGenerator>(using generator: RNG = SystemRandomNumberGenerator()) -> some BackoffStrategy<Duration> {
182178
return EqualJitterBackoffStrategy(base: self, generator: generator)
183179
}
184-
@inlinable public func decorrelatedJitter<RNG: RandomNumberGenerator>(factor: Int, using generator: RNG = SystemRandomNumberGenerator()) -> some BackoffStrategy<Duration> {
185-
return DecorrelatedJitterBackoffStrategy(base: self, generator: generator, factor: factor)
186-
}
187180
}

0 commit comments

Comments
 (0)