Skip to content

Commit ff1dc44

Browse files
committed
added retry
1 parent f20e9a6 commit ff1dc44

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

README.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Network layer for creating different requests like GET, POST, PUT, DELETE etc cu
77

88
## Features
99
- [x] Multiplatform
10+
- [x] Set up amount of attempts if request fails with "Exponential backoff strategy". Exponential backoff is a strategy in which you increase the delays between retries.
1011
- [x] Stand alone package without any dependencies using just Apple's facilities
1112
- [x] Customizable for different requests schemes from classic **CRUD Rest** to what suits to you
1213
- [x] Customizable in term of session
@@ -29,6 +30,11 @@ Network layer for creating different requests like GET, POST, PUT, DELETE etc cu
2930
try await http.get(path: "users")
3031
```
3132

33+
### GET with retry
34+
```swift
35+
try await http.get(path: "users", retry : 5)
36+
```
37+
3238
### POST
3339
```swift
3440
try await http.post(
@@ -56,10 +62,14 @@ Network layer for creating different requests like GET, POST, PUT, DELETE etc cu
5662
### Custom request
5763

5864
```swift
59-
public func send<T>(
60-
with request : URLRequest,
61-
_ taskDelegate: ITaskDelegate? = nil) async throws
62-
-> Http.Response<T> where T : Decodable
65+
/// - Parameters:
66+
/// - request: A URL load request that is independent of protocol or URL scheme
67+
/// - retry: Amount of attempts Default value is 1
68+
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
69+
func sendRetry(
70+
with request : URLRequest,
71+
retry : Int,
72+
_ taskDelegate: ITaskDelegate? = nil
6373
```
6474

6575
# The concept

Sources/async-http-client/proxy/http/Proxy.swift

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,21 @@ public extension Http{
3434
/// - path: Path
3535
/// - query: An array of name-value pairs
3636
/// - headers: A dictionary containing all of the HTTP header fields for a request
37+
/// - retry: Amount of attempts Default value is 1
3738
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
3839
public func get<T>(
3940
path: String,
4041
query : Query? = nil,
4142
headers : Headers? = nil,
43+
retry : Int = 1,
4244
taskDelegate: ITaskDelegate? = nil
4345
) async throws
4446
-> Http.Response<T> where T: Decodable
4547
{
4648

4749
let request = try buildURLRequest(for: path, query: query, headers: headers)
4850

49-
return try await send(with: request, taskDelegate)
51+
return try await send(with: request, retry: retry, taskDelegate)
5052
}
5153

5254
/// POST request
@@ -55,19 +57,21 @@ public extension Http{
5557
/// - body: The data sent as the message body of a request, such as for an HTTP POST or PUT requests
5658
/// - query: An array of name-value pairs
5759
/// - headers: A dictionary containing all of the HTTP header fields for a request
60+
/// - retry: Amount of attempts Default value is 1
5861
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
5962
public func post<T>(
6063
path: String,
6164
body : Encodable? = nil,
6265
query : Query? = nil,
6366
headers : Headers? = nil,
67+
retry : Int = 1,
6468
taskDelegate: ITaskDelegate? = nil
6569
) async throws
6670
-> Http.Response<T> where T: Decodable
6771
{
6872
let request = try buildURLRequest(for: path, method: .post, query: query, body: body, headers: headers)
6973

70-
return try await send(with: request, taskDelegate)
74+
return try await send(with: request, retry: retry, taskDelegate)
7175
}
7276

7377

@@ -77,55 +81,60 @@ public extension Http{
7781
/// - body: The data sent as the message body of a request, such as for an HTTP POST or PUT requests
7882
/// - query: An array of name-value pairs
7983
/// - headers: A dictionary containing all of the HTTP header fields for a request
84+
/// - retry: Amount of attempts Default value is 1
8085
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
8186
public func put<T>(
8287
path: String,
8388
body : Encodable? = nil,
8489
query : Query? = nil,
8590
headers : Headers? = nil,
91+
retry : Int = 1,
8692
taskDelegate: ITaskDelegate? = nil
8793
) async throws
8894
-> Http.Response<T> where T: Decodable
8995
{
9096
let request = try buildURLRequest(for: path, method: .put, query: query, body: body, headers: headers)
9197

92-
return try await send(with: request, taskDelegate)
98+
return try await send(with: request, retry: retry, taskDelegate)
9399
}
94100

95101
/// DELETE request
96102
/// - Parameters:
97103
/// - path: Path
98104
/// - query: An array of name-value pairs
99105
/// - headers: A dictionary containing all of the HTTP header fields for a request
106+
/// - retry: Amount of attempts Default value is 1
100107
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
101108
public func delete<T>(
102109
path: String,
103110
query : Query? = nil,
104111
headers : Headers? = nil,
112+
retry : Int = 1,
105113
taskDelegate: ITaskDelegate? = nil
106114
) async throws
107115
-> Http.Response<T> where T: Decodable
108116
{
109117
let request = try buildURLRequest(for: path, method: .delete, query: query, headers: headers)
110118

111-
return try await send(with: request, taskDelegate)
119+
return try await send(with: request, retry: retry, taskDelegate)
112120
}
113121

114122

115123
/// Send custom request based on the specific request instance
116124
/// - Parameters:
117125
/// - request: A URL load request that is independent of protocol or URL scheme
126+
/// - retry: Amount of attempts Default value is 1
118127
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
119128
public func send<T>(
120129
with request : URLRequest,
121-
_ taskDelegate: ITaskDelegate? = nil) async throws
122-
-> Http.Response<T> where T : Decodable
130+
retry : Int = 1,
131+
_ taskDelegate: ITaskDelegate? = nil
132+
) async throws -> Http.Response<T> where T : Decodable
123133
{
124134

125-
let cfg = config
126-
let reader = cfg.reader
135+
let reader = config.reader
127136

128-
let (data,response) = try await cfg.getSession.data(for: request, delegate: taskDelegate)
137+
let (data,response) = try await sendRetry(with: request, retry: retry, taskDelegate)
129138

130139
let value: T = try reader.read(data: data)
131140

@@ -139,6 +148,40 @@ public extension Http{
139148

140149
private extension Http.Proxy{
141150

151+
/// - Parameters:
152+
/// - request: A URL load request that is independent of protocol or URL scheme
153+
/// - retry: Amount of attempts Default value is 1
154+
/// - taskDelegate: A protocol that defines methods that URL session instances call on their delegates to handle task-level events
155+
func sendRetry(
156+
with request : URLRequest,
157+
retry : Int,
158+
_ taskDelegate: ITaskDelegate? = nil
159+
) async throws -> (Data, URLResponse)
160+
{
161+
guard retry < 0 else { throw HttpProxyError.RetryMustBePositive }
162+
163+
let sesstion = config.getSession
164+
var nextDelay: UInt64 = 1
165+
166+
if retry > 1{
167+
for i in 1...retry-1{
168+
do{
169+
return try await sesstion.data(for: request, delegate: taskDelegate)
170+
}catch{
171+
#if DEBUG
172+
print("retry \(i)")
173+
#endif
174+
}
175+
176+
try? await Task.sleep(nanoseconds: 1_000_000_000 * nextDelay)
177+
178+
nextDelay *= 2
179+
}
180+
}
181+
182+
return try await sesstion.data(for: request, delegate: taskDelegate)
183+
}
184+
142185
/// Url builder method
143186
/// - Parameters:
144187
/// - baseURL: Base url
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// File.swift
3+
//
4+
//
5+
// Created by Igor on 25.02.2023.
6+
//
7+
8+
import Foundation
9+
10+
enum HttpProxyError : Error{
11+
12+
case RetryMustBePositive
13+
14+
}

0 commit comments

Comments
 (0)