Skip to content

[RFC] Add async/await proposal #406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion docs/async-await.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ extension HTTPClient {
}
```

Usage example:
Simple usage example:

```swift
var request = HTTPClientRequest(url: "https://swift.org")
Expand All @@ -168,6 +168,40 @@ default:
}
```

Stream upload and download example using the new `FileHandle` api:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"new" where, in http client?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what this refers to is the new async APIs on Foundation's FileHandle type.

See: https://developer.apple.com/documentation/foundation/filehandle/3766681-bytes


```swift
let readHandle = FileHandle(forReadingFrom: URL(string: "file:///tmp/readfile")!))
let writeHandle = FileHandle(forWritingTo: URL(string: "file:///tmp/writefile")!))

var request = HTTPClientRequest(url: "https://swift.org/echo")
request.method = .POST
request.headers = [
"content-type": "text/plain; charset=UTF-8"
"x-my-fancy-header": "super-awesome"
]
request.body = .stream(readHandle.bytes)

var response = try await client.execute(request, deadline: .now() + .seconds(5))

switch response.status {
case .ok:
Task {
var streamIterator = response.body.makeAsyncIterator()
writeHandle.writeabilityHandler = { handle in
switch try await streamIterator.next() {
case .some(let buffer):
handle.write(buffer.readData(buffer.readableBytes)!)
case .none:
handle.close()
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we can use for await buffer in response.body { … } here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, yes because response.body implements AsyncSequence. However, in this specific example we want to support proper backpressure meaning that we don't want to read more from the body if the writeHandler is not ready to write more data. We therefore wait until we read the next buffer from response.body until writeHandle.writeabilityHandler is called.

}
}
default:
throw MyUnexpectedHTTPStatusError
}
```

- **Why do we have a deadline in the function signature?**
Task deadlines are not part of the Swift 5.5 release. However we think that they are an important tool to not overload the http client accidentally. For this reason we will not default them.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we can't commit to making them happen for Swift 6, it's a clear and important thing we want to support in swift concurrency. So I agree not doing another "our own" thing until then is the right call here.

- **What happened to the Logger?** We will use Task locals to propagate the logger metadata. @slashmo and @ktoso are currently working on this.
Expand Down