@@ -7,6 +7,34 @@ Master advanced retry patterns and optimization techniques.
77
88This guide covers advanced usage patterns, performance optimization, and sophisticated retry strategies for complex scenarios.
99
10+ ## How Retry Mechanism Works
11+
12+ Understanding the retry flow is crucial for effective error handling:
13+
14+ ``` swift
15+ // Configuration: retry: 3 means 3 RETRY attempts
16+ let strategy = RetryStrategy.exponential (
17+ retry : 3 ,
18+ multiplier : 2.0 ,
19+ duration : .seconds (1 )
20+ )
21+ ```
22+
23+ ** Total Execution Flow:**
24+
25+ | Attempt Type | Attempt # | Delay Before | Description |
26+ | --------------| -----------| --------------| -------------|
27+ | Initial | 1 | 0s | First execution (not a retry) |
28+ | Retry | 2 | 1s | First retry after failure |
29+ | Retry | 3 | 2s | Second retry after failure |
30+ | Retry | 4 | 4s | Third retry after failure |
31+
32+ ** Key Points:**
33+ - The ` retry ` parameter specifies the number of ** retry attempts** , not total attempts
34+ - Total attempts = 1 (initial) + N (retries)
35+ - ` retry: 3 ` means ** 4 total attempts** (1 initial + 3 retries)
36+ - ` onFailure ` callback is invoked after ** every** failed attempt, including the initial one
37+
1038## Strategy Deep Dive
1139
1240### Understanding Exponential Backoff
@@ -15,33 +43,36 @@ Exponential backoff progressively increases wait times to avoid overwhelming rec
1543
1644``` swift
1745let strategy = RetryStrategy.exponential (
18- retry : 5 ,
46+ retry : 5 , // 5 retry attempts
1947 multiplier : 2.0 ,
2048 duration : .seconds (1 )
2149)
2250```
2351
24- ** Calculation:** ` delay = baseDuration × multiplier^retryCount `
52+ ** Calculation:** ` delay = baseDuration × multiplier^(attemptNumber - 1) `
53+
54+ | Attempt Type | Total Attempt | Calculation | Delay Before |
55+ | --------------| ---------------| -------------| --------------|
56+ | Initial | 1 | - | 0s (immediate) |
57+ | Retry 1 | 2 | 1 × 2⁰ | 1s |
58+ | Retry 2 | 3 | 1 × 2¹ | 2s |
59+ | Retry 3 | 4 | 1 × 2² | 4s |
60+ | Retry 4 | 5 | 1 × 2³ | 8s |
61+ | Retry 5 | 6 | 1 × 2⁴ | 16s |
2562
26- | Attempt | Calculation | Delay |
27- | ---------| -------------| -------|
28- | 1 | 1 × 2⁰ | 1s |
29- | 2 | 1 × 2¹ | 2s |
30- | 3 | 1 × 2² | 4s |
31- | 4 | 1 × 2³ | 8s |
32- | 5 | 1 × 2⁴ | 16s |
63+ ** Total: 6 attempts (1 initial + 5 retries)**
3364
3465** Multiplier effects:**
3566
3667``` swift
3768// Aggressive backoff (multiplier: 3.0)
38- // 1s → 3s → 9s → 27s → 81s
69+ // Initial: 0s → Retry: 1s → 3s → 9s → 27s → 81s
3970
4071// Moderate backoff (multiplier: 1.5)
41- // 1s → 1.5s → 2.25s → 3.375s → 5.0625s
72+ // Initial: 0s → Retry: 1s → 1.5s → 2.25s → 3.375s → 5.0625s
4273
4374// Slow backoff (multiplier: 1.2)
44- // 1s → 1.2s → 1.44s → 1.728s → 2.074s
75+ // Initial: 0s → Retry: 1s → 1.2s → 1.44s → 1.728s → 2.074s
4576```
4677
4778### Jitter: Preventing Thundering Herd
@@ -50,7 +81,7 @@ When multiple clients retry simultaneously, they can overwhelm a recovering serv
5081
5182``` swift
5283let strategy = RetryStrategy.exponentialWithJitter (
53- retry : 5 ,
84+ retry : 5 , // 5 retry attempts
5485 jitterFactor : 0.2 , // ±20% randomization
5586 maxInterval : .seconds (30 ), // Cap at 30 seconds
5687 multiplier : 2.0 ,
@@ -60,17 +91,17 @@ let strategy = RetryStrategy.exponentialWithJitter(
6091
6192** Without jitter:**
6293```
63- Client 1: 0s → 1s → 2s → 4s → 8s
64- Client 2: 0s → 1s → 2s → 4s → 8s
65- Client 3: 0s → 1s → 2s → 4s → 8s
94+ Client 1: 0s(init) → 1s → 2s → 4s → 8s → 16s
95+ Client 2: 0s(init) → 1s → 2s → 4s → 8s → 16s
96+ Client 3: 0s(init) → 1s → 2s → 4s → 8s → 16s
6697All hit server simultaneously! 💥
6798```
6899
69100** With jitter:**
70101```
71- Client 1: 0s → 0.9s → 2.1s → 3.8s → 8.2s
72- Client 2: 0s → 1.1s → 1.9s → 4.3s → 7.7s
73- Client 3: 0s → 0.8s → 2.2s → 3.9s → 8.1s
102+ Client 1: 0s(init) → 0.9s → 2.1s → 3.8s → 8.2s → 15.7s
103+ Client 2: 0s(init) → 1.1s → 1.9s → 4.3s → 7.7s → 16.4s
104+ Client 3: 0s(init) → 0.8s → 2.2s → 3.9s → 8.1s → 15.8s
74105Traffic spread out! ✅
75106```
76107
@@ -80,17 +111,19 @@ Prevent delays from growing unbounded:
80111
81112``` swift
82113.exponentialWithJitter (
83- retry : 10 ,
114+ retry : 10 , // 10 retry attempts = 11 total
84115 jitterFactor : 0.1 ,
85- maxInterval : .seconds (60 ), // Never wait more than 60 seconds
116+ maxInterval : .seconds (60 ), // Never wait more than 60 seconds
86117 multiplier : 2.0 ,
87118 duration : .seconds (1 )
88119)
89120```
90121
91- ** Without cap:** 1s → 2s → 4s → 8s → 16s → 32s → 64s → 128s → 256s...
122+ ** Without cap:**
123+ Initial → 1s → 2s → 4s → 8s → 16s → 32s → 64s → 128s → 256s → 512s
92124
93- ** With 60s cap:** 1s → 2s → 4s → 8s → 16s → 32s → 60s → 60s → 60s...
125+ ** With 60s cap:**
126+ Initial → 1s → 2s → 4s → 8s → 16s → 32s → 60s → 60s → 60s → 60s
94127
95128## Advanced Patterns
96129
@@ -132,7 +165,8 @@ func fetchWithConditionalRetry() async throws -> Data {
132165 } catch let error as RetryPolicyError {
133166 switch error {
134167 case .retryLimitExceeded :
135- // Retry linit exceeded
168+ // All retry attempts exhausted
169+ print (" Retry limit exceeded after multiple attempts" )
136170 throw error
137171 }
138172 }
@@ -200,6 +234,7 @@ actor AdaptiveRetryService {
200234 private func selectStrategy () -> RetryPolicyStrategy {
201235 if consecutiveFailures >= maxConsecutiveFailures {
202236 // System under stress - use conservative strategy
237+ // 1 initial + 3 retries with longer delays
203238 return .exponentialWithJitter (
204239 retry : 3 ,
205240 jitterFactor : 0.3 ,
@@ -209,6 +244,7 @@ actor AdaptiveRetryService {
209244 )
210245 } else {
211246 // Normal operation - use standard strategy
247+ // 1 initial + 4 retries
212248 return .exponential (
213249 retry : 4 ,
214250 multiplier : 2.0 ,
0 commit comments