Skip to content
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

whenComplete does not work without wait() #564

Closed
vinamelody opened this issue Feb 26, 2022 · 2 comments
Closed

whenComplete does not work without wait() #564

vinamelody opened this issue Feb 26, 2022 · 2 comments

Comments

@vinamelody
Copy link

vinamelody commented Feb 26, 2022

Hi, I'm new with swift-nio and want to make a simple swift cli tool that sends an API request. I tried following the readme to do something like this in my swift code

httpClient.execute(request: request).whenComplete { result in
            dump(result)
            switch result {
            case .failure(let error):
                print("Error \(error)")
            case .success(let response):
                print("Response: \(response)")
                if response.status == .ok {
                    print("Response: \(response)")
                } else {
                    print("Response is not ok")
                }
            }
        }

the output error is

▿ Swift.Result<AsyncHTTPClient.HTTPClient.Response, Swift.Error>.failure
  ▿ failure: HTTPClientError.cancelled
    - code: AsyncHTTPClient.HTTPClientError.(unknown context at $10587c078).Code.cancelled

One google result leads me to this same problem https://stackoverflow.com/questions/59434813/how-to-use-async-http-client
and the answer is, rather than using whenComplete , i should do it like this

let future = httpClient.execute(request: request)
        let response = try future.wait()
        print(response)

How can I make the whenComplete works?

When I just add a line try future.wait() ... it works but i need to discard its response too?

Thanks for your help!

@dnadoba
Copy link
Collaborator

dnadoba commented Feb 27, 2022

The problem is probably that httpClient is shutdown before the request is finished and therefore canceled.
Maybe you have a defer { httpClient.shutdonw() } or similar in your code which is executed immediately after you started your request because whenComplete returns immediately. On the other hand, .wait() waits until the request is finished and the httpClient is only shutdown afterwards. Can you show as the code which creates and also eventually shutdowns the HTTPClient?

Similar issue: #477

BTW: If you can use Swift 5.5.2 or higher, I would suggest you to use the new async/await API. Here is an example how to use it:

let httpClient = HTTPClient(eventLoopGroupProvider: .createNew)
do {
let request = HTTPClientRequest(url: "https://xkcd.com/info.0.json")
let response = try await httpClient.execute(request, timeout: .seconds(30))
print("HTTP head", response)
let body = try await response.body.collect(upTo: 1024 * 1024) // 1 MB
// we use an overload defined in `NIOFoundationCompat` for `decode(_:from:)` to
// efficiently decode from a `ByteBuffer`
let comic = try JSONDecoder().decode(Comic.self, from: body)
dump(comic)
} catch {
print("request failed:", error)
}
// it is important to shutdown the httpClient after all requests are done, even if one failed
try await httpClient.shutdown()

@vinamelody
Copy link
Author

Hi, ah okay thanks I guess this code works for now.. yeah for some reasons, i'm not able to use async/await for now
Thanks for the help @dnadoba

let future = httpClient.execute(request: request)        
        defer {
            _ = try? future.wait() // --> gotta discard the result here
            try? httpClient.syncShutdown()
        }
        
        httpClient.execute(request: request).whenComplete { result in
            dump(result)
            switch result {
            case .failure(let error):
                print("Error \(error)")
            case .success(let response):
                print("Response: \(response)")
                if response.status == .ok {
                    print("Response: \(response)")
                } else {
                    print("Response is not ok")
                }
            }
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants