0

I have a long running task that may raise an exception randomly. This task is an infinite loop: it's not expected to finish or to be awaited. It is tied to an instance of a specific class, I cancel the task when the instance is garbage collected.

I'd like to raise potential errors "outside" of this task but failed to do so.

    def start_worker(self):
        self.worker = asyncio.create_task(
            self._worker()
        )
        def should_never_be_done(t: asyncio.Task):
            if t.exception() is not None:
                logger.exception(t.exception())
                raise t.exception()
            raise Exception(
                "_worker task is done, yet it should never finish")
        self.worker.add_done_callback(should_never_be_done)

I see the exception in my log, but it doesn't crash the whole app, which I want in this case instead of a silent fail leading to infinite loadings in my UI.

This related question show only how to log the error but do not aim at raising it, hence the separate question.

Eric Burel
  • 3,790
  • 2
  • 35
  • 56
  • In Python 3.11, use the context manager for this. – Сергей Кох Jul 04 '23 at 16:17
  • Please provide a [mcve]. The code snippet here is neither complete nor does it communicate what you described in prose. It is just a dump of a few lines of your program. – Daniil Fajnberg Jul 04 '23 at 16:27
  • Also, this seems like a duplicate of [this question](https://stackoverflow.com/questions/66293545). Just don't leave a task dangling without eventually awaiting it _somewhere_. – Daniil Fajnberg Jul 04 '23 at 16:44
  • Right for the duplicate, the answer is not satisfactory as it imply awaiting the tasks but the question is indeed similar. – Eric Burel Jul 11 '23 at 11:34

1 Answers1

0

well, the add_done_callback is as good as it gets: if you see the exception in your logs, you had catch the exception - now, just do whatever you want with it.

Either just relaunch your worker, or create an event or queue with which you can sinalize to the rest of the application they should be done, or, to just crash everything, just close the event loop right there:

        ...
        def should_never_be_done(t: asyncio.Task):
            if t.exception() is not None:
                logger.exception(t.exception())
                # Trainwreck: 
                asyncio.get_running_loop().close()
                
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • I think the "trainwreck" part is what I missed : feel free to add this answer in https://stackoverflow.com/questions/66293545/asyncio-re-raise-exception-from-a-task which seems to be the same question – Eric Burel Jul 11 '23 at 11:35