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.
This commit is contained in:
parent
8e882235be
commit
fe08311c19
|
@ -73,7 +73,8 @@ class FilesystemController(BaseController):
|
|||
self.answers.setdefault('manual', [])
|
||||
self._monitor = None
|
||||
self._crash_reports = {}
|
||||
self._probe_once_task = SingleInstanceTask(self._probe_once)
|
||||
self._probe_once_task = SingleInstanceTask(
|
||||
self._probe_once, propagate_errors=False)
|
||||
self._probe_task = SingleInstanceTask(self._probe)
|
||||
|
||||
async def _probe_once(self, restricted):
|
||||
|
|
|
@ -23,13 +23,14 @@ def _done(fut):
|
|||
pass
|
||||
|
||||
|
||||
def schedule_task(coro):
|
||||
def schedule_task(coro, propagate_errors=True):
|
||||
loop = asyncio.get_event_loop()
|
||||
if asyncio.iscoroutine(coro):
|
||||
task = asyncio.Task(coro)
|
||||
else:
|
||||
task = coro
|
||||
task.add_done_callback(_done)
|
||||
if propagate_errors:
|
||||
task.add_done_callback(_done)
|
||||
loop.call_soon(asyncio.ensure_future, task)
|
||||
return task
|
||||
|
||||
|
@ -41,8 +42,9 @@ async def run_in_thread(func, *args):
|
|||
|
||||
class SingleInstanceTask:
|
||||
|
||||
def __init__(self, func):
|
||||
def __init__(self, func, propagate_errors=True):
|
||||
self.func = func
|
||||
self.propagate_errors = propagate_errors
|
||||
self.task = None
|
||||
|
||||
async def start(self, *args, **kw):
|
||||
|
@ -52,7 +54,9 @@ class SingleInstanceTask:
|
|||
await self.task
|
||||
except BaseException:
|
||||
pass
|
||||
self.task = schedule_task(self.func(*args, **kw))
|
||||
self.task = schedule_task(
|
||||
self.func(*args, **kw), self.propagate_errors)
|
||||
return self.task
|
||||
|
||||
def start_sync(self, *args, **kw):
|
||||
return schedule_task(self.start(*args, **kw))
|
||||
|
|
Loading…
Reference in New Issue