I'm new to Swift and async/await; I'd like to know if there is a clean way to pass a single value between Tasks in async/await.
As an example motivating use case of what I mean: imagine that I have some protocol that can async send and receive messages in some shared stream. In the message protocol, I can set a message ID on the request, and when a response comes back with the same message ID, I want to asynchronously deliver it. A simple unary RPC.
What I have today looks like this:
func rpc(_ req: Request) async throws -> Response {
return try await withCheckedThrowingContinuation { continuation in
Task {
let msgID = await self.wantResponses.store(continuation)
req.msgID = msgID
await self.send(req)
}
}
}
...where some other Task is reading the messages from the stream, matching them up with the continuation
s stored in wantResponses
, and calling .resume(returning: resp)
.
This works, but it feels very awkward. I'm having to nest my logic 2-levels deep because withCheckedThrowingContinuation
takes a closure, and because that closure doesn't itself run in an async
context.
What I'd really like is something akin to a Future, but async/await native and without the closure.
E.g.
func rpc(_ req: Request) async throws -> Response {
let future = AsyncFuture<Response, Error>()
let msgID = await self.wantResponses.store(future.continuation)
req.msgID = msgID
await self.send(req)
return try await future.value
}
Does anything like this exist?
I'm really struggling to figure out a good way to use async/await
if the thing that produces a result is in a different Task that is not a direct child of the thing that wants to await
for that result.