Skip to content

Commit bc98971

Browse files
committed
Add an option to log exceptions raised by tasks
It is common that users forget to handle exceptions properly in their tasks, and since services tasks are supposed to run forever, there are no many opportunities to await for their completion appropriately and handle the failure. With this at least we make sure we will get a log message when a task raises an exception, so we can at least know what happened and they just silently disappear. Signed-off-by: Leandro Lucarella <[email protected]>
1 parent e39f292 commit bc98971

File tree

1 file changed

+18
-0
lines changed

1 file changed

+18
-0
lines changed

src/frequenz/core/asyncio.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@
2020
import asyncio
2121
import collections.abc
2222
import contextvars
23+
import logging
2324
from types import TracebackType
2425
from typing import Any, Protocol, Self, TypeVar, runtime_checkable
2526

27+
_logger = logging.getLogger(__name__)
28+
29+
2630
TaskReturnT = TypeVar("TaskReturnT")
2731
"""The type of the return value of a task."""
2832

@@ -194,6 +198,7 @@ def create_task(
194198
*,
195199
name: str | None = None,
196200
context: contextvars.Context | None = None,
201+
log_exception: bool = True,
197202
) -> asyncio.Task[TaskReturnT]:
198203
"""Start a managed task.
199204
@@ -212,13 +217,26 @@ def create_task(
212217
coro: The coroutine to be managed.
213218
name: The name of the task.
214219
context: The context to be used for the task.
220+
log_exception: Whether to log exceptions raised by the task.
215221
216222
Returns:
217223
The new task.
218224
"""
219225
task = self._task_creator.create_task(coro, name=name, context=context)
220226
self._tasks.add(task)
221227
task.add_done_callback(self._tasks.discard)
228+
229+
if log_exception:
230+
231+
def _log_exception(task: asyncio.Task[TaskReturnT]) -> None:
232+
try:
233+
task.result()
234+
except asyncio.CancelledError:
235+
pass
236+
except BaseException: # pylint: disable=broad-except
237+
_logger.exception("%s: Task %r raised an exception", self, task)
238+
239+
task.add_done_callback(_log_exception)
222240
return task
223241

224242
def cancel(self, msg: str | None = None) -> None:

0 commit comments

Comments
 (0)