Commit Graph

11 Commits

Author SHA1 Message Date
Dan Bungert 98a2ff8647 async_helpers: simplify task done check
Another version of the task-created-yet problem is the non-blocking
check to see if it is done or not.  Add a wrapper here to simplify
calling code.
2023-03-13 15:50:33 -06:00
Dan Bungert 075b06ce70 async_helpers: make SingleInstanceTask.wait safer
SingleInstanceTask has distinct steps for creation of the object, and
starting the task.  If a different coroutine is waiting on the
SingleInstanceTask, it isn't safe to directly call
SingleInstanceTask.wait() as the task may or may not have been created
yet.

Existing code usage of SingleInstanceTask is in 4 categories, with
reguards to SingleInstanceTask.wait():
1) using SingleInstanceTask without using SingleInstanceTask.wait().
   This is unchanged.
2) using SingleInstanceTask.wait without a check on task is not None.
   This may be safe now, but is fragile in the face of innocent-looking
   refactors around the SingleInstanceTask.
3) using SingleInstanceTask.wait after confirming that the task is not
   None.  This is fine but a leaky abstraction.
4) directly waiting on the SingleInstanceTask.task.  Another leaky
   abstraction, but it's solving a cancellation problem.  Leaving this
   alone.

By enhancing SingleInstanceTask.wait(), cases 2 and 3 are improved.  The
code not checking the task today is made safer, and the code checking
the task today can be simplified.
2023-03-13 15:50:33 -06:00
Olivier Gayot b0ced5afb0 async: add helper to run fire-and-forget tasks
calling asyncio.create_task(...) without storing a reference to the
result can lead to the task being garbage collected before it actually
executed.

https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task

The documentation gives an example of a reliable way to run
fire-and-forget background tasks.

This patch adds an helper to do exactly that.

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2023-01-24 12:50:23 +01:00
Olivier Gayot f0e5c19ee7 loop: replace use of asyncio.get_event_loop
The behavior of asyncio.get_event_loop() will change in a future Python
version. It is deprecated starting Python 3.10.

The functions that we can use instead are:

 * asyncio.new_event_loop() - which creates a new event loop
 * asyncio.get_running_loop() - which returns the event loop only if it
   is already running

Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
2022-10-07 18:45:11 +02:00
Dan Bungert 77119a8e0b SingleInstanceTask: add cancel_restart
cancel_restart is a mode for SingleInstanceTask that changes the
behavior when starting the task - if the task is already running, do not
cancel it to start another.
2022-05-25 10:25:00 -06:00
Michael Hudson-Doyle a03a336bd7 translate concurrent.futures.CancelledError to asyncio.CancelledError
apparently cancelling something that is running in a thread leads to a different
exception class being raised...
2020-04-02 12:15:06 +13:00
Michael Hudson-Doyle 570472315d Add SingleInstanceTask.wait
this can be called without having to worry about the task being
cancelled out from under you
2019-12-20 11:00:46 +13:00
Michael Hudson-Doyle de18cc977f make SingleInstanceTask.start_sync set self.task synchronously 2019-12-16 12:33:19 +13:00
Michael Hudson-Doyle fe08311c19 stop block probing failures from crashing the process
There is a common problem in concurrent / asynchronous code of what to
do with unhandled exceptions. If a (conceptual) thread of execution
fails, there's no guarantee (and no way of telling) if there's anything
listening.  By default, I chose to have a failing task propagate the
exception up to the run loop for two reasons:

 1) Unhandled exceptions are generally bad
 2) urwid.ExitMainLoop needs to be propagated to the run loop to have
    any effect

But this means that tasks that are expected to fail (and have this
failure handled) like block probing crash the process, which is
obviously a Bad Thing. This branch adds a way to turn off exception
propagation per-task, which is a bit hackish but works ok it seems.
2019-12-15 09:45:14 +13:00
Michael Hudson-Doyle 992e131b5f squash all exceptions when cancelling the task in SingleInstanceTask
otherwise restarting a failed task just raises the exception from the previous
failure
2019-12-13 10:05:23 +13:00
Michael Hudson-Doyle 08e081415d move async_helpers to subiquitycore 2019-12-13 10:04:02 +13:00