Skip to content

Commit e720e1c

Browse files
Johannes Weissweissi
Johannes Weiss
authored andcommitted
use NIOSingletons EventLoops/NIOThreadPool instead of spawning new
1 parent 62c06d4 commit e720e1c

File tree

9 files changed

+166
-117
lines changed

9 files changed

+166
-117
lines changed

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ let package = Package(
2121
.library(name: "AsyncHTTPClient", targets: ["AsyncHTTPClient"]),
2222
],
2323
dependencies: [
24-
.package(url: "https://github.com/apple/swift-nio.git", from: "2.50.0"),
24+
.package(url: "https://github.com/apple/swift-nio.git", from: "2.58.0"),
2525
.package(url: "https://github.com/apple/swift-nio-ssl.git", from: "2.22.0"),
2626
.package(url: "https://github.com/apple/swift-nio-http2.git", from: "1.19.0"),
2727
.package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.13.0"),
28-
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.11.4"),
28+
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.19.0"),
2929
.package(url: "https://github.com/apple/swift-log.git", from: "1.4.4"),
3030
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.0.2"),
3131
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.0.0"),

README.md

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,10 @@ and `AsyncHTTPClient` dependency to your target:
2727

2828
The code snippet below illustrates how to make a simple GET request to a remote server.
2929

30-
Please note that the example will spawn a new `EventLoopGroup` which will _create fresh threads_ which is a very costly operation. In a real-world application that uses [SwiftNIO](https://github.com/apple/swift-nio) for other parts of your application (for example a web server), please prefer `eventLoopGroupProvider: .shared(myExistingEventLoopGroup)` to share the `EventLoopGroup` used by AsyncHTTPClient with other parts of your application.
31-
32-
If your application does not use SwiftNIO yet, it is acceptable to use `eventLoopGroupProvider: .createNew` but please make sure to share the returned `HTTPClient` instance throughout your whole application. Do not create a large number of `HTTPClient` instances with `eventLoopGroupProvider: .createNew`, this is very wasteful and might exhaust the resources of your program.
33-
3430
```swift
3531
import AsyncHTTPClient
3632

37-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
33+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
3834

3935
/// MARK: - Using Swift Concurrency
4036
let request = HTTPClientRequest(url: "https://apple.com/")
@@ -78,7 +74,7 @@ The default HTTP Method is `GET`. In case you need to have more control over the
7874
```swift
7975
import AsyncHTTPClient
8076

81-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
77+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
8278
do {
8379
var request = HTTPClientRequest(url: "https://apple.com/")
8480
request.method = .POST
@@ -103,9 +99,10 @@ try await httpClient.shutdown()
10399
```swift
104100
import AsyncHTTPClient
105101

106-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
102+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
107103
defer {
108-
try? httpClient.syncShutdown()
104+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
105+
try! httpClient.syncShutdown()
109106
}
110107

111108
var request = try HTTPClient.Request(url: "https://apple.com/", method: .POST)
@@ -129,15 +126,15 @@ httpClient.execute(request: request).whenComplete { result in
129126
### Redirects following
130127
Enable follow-redirects behavior using the client configuration:
131128
```swift
132-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
129+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton,
133130
configuration: HTTPClient.Configuration(followRedirects: true))
134131
```
135132

136133
### Timeouts
137134
Timeouts (connect and read) can also be set using the client configuration:
138135
```swift
139136
let timeout = HTTPClient.Configuration.Timeout(connect: .seconds(1), read: .seconds(1))
140-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
137+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton,
141138
configuration: HTTPClient.Configuration(timeout: timeout))
142139
```
143140
or on a per-request basis:
@@ -151,7 +148,7 @@ The following example demonstrates how to count the number of bytes in a streami
151148

152149
#### Using Swift Concurrency
153150
```swift
154-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
151+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
155152
do {
156153
let request = HTTPClientRequest(url: "https://apple.com/")
157154
let response = try await httpClient.execute(request, timeout: .seconds(30))
@@ -251,7 +248,7 @@ asynchronously, while reporting the download progress at the same time, like in
251248
example:
252249

253250
```swift
254-
let client = HTTPClient(eventLoopGroupProvider: .createNew)
251+
let client = HTTPClient(eventLoopGroupProvider: .singleton)
255252
let request = try HTTPClient.Request(
256253
url: "https://swift.org/builds/development/ubuntu1804/latest-build.yml"
257254
)
@@ -275,7 +272,7 @@ client.execute(request: request, delegate: delegate).futureResult
275272
### Unix Domain Socket Paths
276273
Connecting to servers bound to socket paths is easy:
277274
```swift
278-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
275+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
279276
httpClient.execute(
280277
.GET,
281278
socketPath: "/tmp/myServer.socket",
@@ -285,7 +282,7 @@ httpClient.execute(
285282

286283
Connecting over TLS to a unix domain socket path is possible as well:
287284
```swift
288-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
285+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
289286
httpClient.execute(
290287
.POST,
291288
secureSocketPath: "/tmp/myServer.socket",
@@ -312,7 +309,7 @@ The exclusive use of HTTP/1 is possible by setting `httpVersion` to `.http1Only`
312309
var configuration = HTTPClient.Configuration()
313310
configuration.httpVersion = .http1Only
314311
let client = HTTPClient(
315-
eventLoopGroupProvider: .createNew,
312+
eventLoopGroupProvider: .singleton,
316313
configuration: configuration
317314
)
318315
```

Sources/AsyncHTTPClient/Docs.docc/index.md

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@ and `AsyncHTTPClient` dependency to your target:
3131

3232
The code snippet below illustrates how to make a simple GET request to a remote server.
3333

34-
Please note that the example will spawn a new `EventLoopGroup` which will _create fresh threads_ which is a very costly operation. In a real-world application that uses [SwiftNIO](https://github.com/apple/swift-nio) for other parts of your application (for example a web server), please prefer `eventLoopGroupProvider: .shared(myExistingEventLoopGroup)` to share the `EventLoopGroup` used by AsyncHTTPClient with other parts of your application.
35-
36-
If your application does not use SwiftNIO yet, it is acceptable to use `eventLoopGroupProvider: .createNew` but please make sure to share the returned `HTTPClient` instance throughout your whole application. Do not create a large number of `HTTPClient` instances with `eventLoopGroupProvider: .createNew`, this is very wasteful and might exhaust the resources of your program.
37-
3834
```swift
3935
import AsyncHTTPClient
4036

41-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
37+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
38+
defer {
39+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
40+
try! httpClient.syncShutdown()
41+
}
4242

4343
/// MARK: - Using Swift Concurrency
4444
let request = HTTPClientRequest(url: "https://apple.com/")
@@ -82,7 +82,12 @@ The default HTTP Method is `GET`. In case you need to have more control over the
8282
```swift
8383
import AsyncHTTPClient
8484

85-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
85+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
86+
defer {
87+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
88+
try! httpClient.syncShutdown()
89+
}
90+
8691
do {
8792
var request = HTTPClientRequest(url: "https://apple.com/")
8893
request.method = .POST
@@ -107,9 +112,10 @@ try await httpClient.shutdown()
107112
```swift
108113
import AsyncHTTPClient
109114

110-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
115+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
111116
defer {
112-
try? httpClient.syncShutdown()
117+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
118+
try! httpClient.syncShutdown()
113119
}
114120

115121
var request = try HTTPClient.Request(url: "https://apple.com/", method: .POST)
@@ -133,15 +139,15 @@ httpClient.execute(request: request).whenComplete { result in
133139
#### Redirects following
134140
Enable follow-redirects behavior using the client configuration:
135141
```swift
136-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
142+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton,
137143
configuration: HTTPClient.Configuration(followRedirects: true))
138144
```
139145

140146
#### Timeouts
141147
Timeouts (connect and read) can also be set using the client configuration:
142148
```swift
143149
let timeout = HTTPClient.Configuration.Timeout(connect: .seconds(1), read: .seconds(1))
144-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew,
150+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton,
145151
configuration: HTTPClient.Configuration(timeout: timeout))
146152
```
147153
or on a per-request basis:
@@ -155,7 +161,12 @@ The following example demonstrates how to count the number of bytes in a streami
155161

156162
##### Using Swift Concurrency
157163
```swift
158-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
164+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
165+
defer {
166+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
167+
try! httpClient.syncShutdown()
168+
}
169+
159170
do {
160171
let request = HTTPClientRequest(url: "https://apple.com/")
161172
let response = try await httpClient.execute(request, timeout: .seconds(30))
@@ -255,7 +266,12 @@ asynchronously, while reporting the download progress at the same time, like in
255266
example:
256267

257268
```swift
258-
let client = HTTPClient(eventLoopGroupProvider: .createNew)
269+
let client = HTTPClient(eventLoopGroupProvider: .singleton)
270+
defer {
271+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
272+
try! httpClient.syncShutdown()
273+
}
274+
259275
let request = try HTTPClient.Request(
260276
url: "https://swift.org/builds/development/ubuntu1804/latest-build.yml"
261277
)
@@ -279,7 +295,12 @@ client.execute(request: request, delegate: delegate).futureResult
279295
#### Unix Domain Socket Paths
280296
Connecting to servers bound to socket paths is easy:
281297
```swift
282-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
298+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
299+
defer {
300+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
301+
try! httpClient.syncShutdown()
302+
}
303+
283304
httpClient.execute(
284305
.GET,
285306
socketPath: "/tmp/myServer.socket",
@@ -289,7 +310,12 @@ httpClient.execute(
289310

290311
Connecting over TLS to a unix domain socket path is possible as well:
291312
```swift
292-
let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
313+
let httpClient = HTTPClient(eventLoopGroupProvider: .singleton)
314+
defer {
315+
// Shutdown is guaranteed to work if it's done precisely once (which is the case here).
316+
try! httpClient.syncShutdown()
317+
}
318+
293319
httpClient.execute(
294320
.POST,
295321
secureSocketPath: "/tmp/myServer.socket",
@@ -316,7 +342,7 @@ The exclusive use of HTTP/1 is possible by setting ``HTTPClient/Configuration/ht
316342
var configuration = HTTPClient.Configuration()
317343
configuration.httpVersion = .http1Only
318344
let client = HTTPClient(
319-
eventLoopGroupProvider: .createNew,
345+
eventLoopGroupProvider: .singleton,
320346
configuration: configuration
321347
)
322348
```

0 commit comments

Comments
 (0)