-
Notifications
You must be signed in to change notification settings - Fork 65
fix: create raceAndCancelPending proc #1175
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
base: master
Are you sure you want to change the base?
Changes from all commits
c3114d2
661d2ce
188b119
e21b0e4
888385e
231b581
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ | |
|
|
||
| {.push raises: [].} | ||
|
|
||
| import sequtils | ||
| import chronos | ||
|
|
||
| type AllFuturesFailedError* = object of CatchableError | ||
|
|
@@ -31,3 +32,19 @@ proc anyCompleted*[T](futs: seq[Future[T]]): Future[Future[T]] {.async.} = | |
|
|
||
| let index = requests.find(raceFut) | ||
| requests.del(index) | ||
|
|
||
| proc raceAndCancelPending*( | ||
| futs: seq[SomeFuture] | ||
| ): Future[void] {.async: (raises: [ValueError, CancelledError]).} = | ||
|
Comment on lines
+36
to
+38
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it should indeed, mostly because race is declared that way - that said, returning the future is actually of limited use since the value type is lost - most uses of The other risk is that one forgets that more than one future might be finished by the time |
||
| ## Executes a race between the provided sequence of futures. | ||
| ## Cancels any remaining futures that have not yet completed. | ||
| ## | ||
| ## - `futs`: A sequence of futures to race. | ||
| ## | ||
| ## Raises: | ||
| ## - `ValueError` if the sequence of futures is empty. | ||
| ## - `CancelledError` if the operation is canceled. | ||
| try: | ||
| discard await race(futs) | ||
| finally: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there is no need for finally .. in particular, if |
||
| await noCancel allFutures(futs.filterIt(not it.finished).mapIt(it.cancelAndWait)) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| {.used.} | ||
|
|
||
| # Nim-Libp2p | ||
| # Copyright (c) 2023 Status Research & Development GmbH | ||
| # Licensed under either of | ||
| # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) | ||
| # * MIT license ([LICENSE-MIT](LICENSE-MIT)) | ||
| # at your option. | ||
| # This file may not be copied, modified, or distributed except according to | ||
| # those terms. | ||
|
|
||
| import ../helpers | ||
| import ../../libp2p/utils/future | ||
|
|
||
| suite "Utils Future": | ||
| asyncTest "All Pending Tasks are canceled when returned future is canceled": | ||
| proc longRunningTaskA() {.async.} = | ||
| await sleepAsync(10.seconds) | ||
|
|
||
| proc longRunningTaskB() {.async.} = | ||
| await sleepAsync(10.seconds) | ||
|
|
||
| let | ||
| futureA = longRunningTaskA() | ||
| futureB = longRunningTaskB() | ||
|
|
||
| # Both futures should be canceled when raceCancel is called | ||
| await raceAndCancelPending(@[futureA, futureB]).cancelAndWait() | ||
| check futureA.cancelled | ||
| check futureB.cancelled | ||
|
|
||
| # Test where one task finishes immediately, leading to the cancellation of the pending task | ||
| asyncTest "Cancel Pending Tasks When One Completes": | ||
| proc quickTask() {.async.} = | ||
| return | ||
|
|
||
| proc slowTask() {.async.} = | ||
| await sleepAsync(10.seconds) | ||
|
|
||
| let | ||
| futureQuick = quickTask() | ||
| futureSlow = slowTask() | ||
|
|
||
| # The quick task finishes, so the slow task should be canceled | ||
| await raceAndCancelPending(@[futureQuick, futureSlow]) | ||
| check futureQuick.finished | ||
| check futureSlow.cancelled | ||
|
|
||
| asyncTest "raceAndCancelPending with AsyncEvent": | ||
| let asyncEvent = newAsyncEvent() | ||
| let fut1 = asyncEvent.wait() | ||
| let fut2 = newAsyncEvent().wait() | ||
| asyncEvent.fire() | ||
| await raceAndCancelPending(@[fut1, fut2]) | ||
|
|
||
| check fut1.finished | ||
| check fut2.cancelled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about
raceAndCancelPending->raceAndCancel?