I'm trying to write a Swift function that is similar to the Rx race function that has the following signature:
/// Returns the first value that is returned by one of the supplied closures
/// or throws the first error that is encountered
func first<Success: Sendable>(
_ t1: @escaping () async throws -> Success,
_ t2: @escaping () async throws -> Success
) async throws -> Success
A usage example would be to load identical data from servers, and cancel after the first request has finished, or adding timeouts to arbitrary tasks:
This, however, doesn't return immediately after one group has finished but waits until all tasks have finished.
Are there any alternative implementations that would fulfil my needs?
This could be happening for you because the child tasks you add to the group do not support cancellation themselves: group.cancelAll() essentially just sets some atomic boolean flag on the subtasks, but it doesn't abort or otherwise discard them — tasks themselves have to decide internally when it's appropriate to short-circuit (otherwise this forced halting could break lots of invariants).
You might want to write either if Task.isCancelled { return } or try Task.checkCancellation() in your long-running functions.
I'd suggest using the Task.sleep(for: .seconds...) but that looks okey.
In general we're interested in both deadlines (rather than timeouts) for tasks as well as such operations I think. Deadlines were blocked by not having time units in stdlib before, but now we could revisit the topic.
And a first() could be implemented with ... so it is for arbitrary amounts of child tasks as well.