This is a little helper script that can be used to wait for a single asyncio
task to finish, then cancel other waiting tasks.
My use-case for this is:
- waiting on user input
- ...while waiting on cancellation events input (via pub-sub)
- ...while waiting on errors
when ANY of these events occurs, we should cancel the other running tasks.
The function takes in a list of asyncio.Tasks
and returns a list of the respective results (or None
, if the task was cancelled), i.e.
task_1_result, task_2_result, ... = await wait_for_one_cancel_others(
task_1,
task_2,
...
)
# `task_1_result` can be a value (if task 1 finishes) or `None` (if task 2 finishes)
# `task_2_result` can be None (if task 1 finishes) or a value (if task 2 finishes)
# ...and so forth
For an example:
sensor_success, cancelled_success = await wait_for_one_cancel_others(
asyncio.create_task(self.wait_for_all_sensors()),
asyncio.create_task(self.wait_for_cancellation(next_order_item))
)
# Here, if we had a sensor input, `sensor_success` would return `True` and
# `cancelled_success` would be `None`.
#
# If there was a cancellation event, then instead `sensor_success` would be `None`
# and `cancelled_success` would be `True`
or perhaps with a timeout:
sensor_success, cancelled_success, timeout_success = await wait_for_one_cancel_others(
asyncio.create_task(self.wait_for_all_sensors()),
asyncio.create_task(self.wait_for_cancellation(next_order_item)),
asyncio.create_task(asyncio.sleep(delay=10.0, result=True)) # NOTE: the `result=True` bit here, so the function returns True on timeout
)
# if the task times out, then sensor_success, cancelled_success would be None,
# and timeout_success would be True
Here, we're waiting on some sensor input WHILE monitoring for a cancellation event (via NATS). When either one of these events occurs, it will cancel the other tasks passed into the function.
Important
It's important to note that, technically, two tasks can finish at the same time. This means you will get multiple non-null return values. You can mitigate this from occuring by ensuring a task does not return without being cancelled.