55 lines
1.7 KiB
Python
55 lines
1.7 KiB
Python
|
|
# utils/task_tracker.py
|
||
|
|
"""
|
||
|
|
Tracked asyncio task creation utility.
|
||
|
|
|
||
|
|
Replaces fire-and-forget asyncio.create_task() calls with error-logging wrappers
|
||
|
|
so that exceptions in background tasks are never silently swallowed.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import asyncio
|
||
|
|
from typing import Optional, Coroutine, Set
|
||
|
|
from utils.logger import get_logger
|
||
|
|
|
||
|
|
logger = get_logger("task_tracker")
|
||
|
|
|
||
|
|
# Keep references to running tasks so they aren't garbage-collected
|
||
|
|
_active_tasks: Set[asyncio.Task] = set()
|
||
|
|
|
||
|
|
|
||
|
|
def create_tracked_task(
|
||
|
|
coro: Coroutine,
|
||
|
|
task_name: Optional[str] = None,
|
||
|
|
) -> asyncio.Task:
|
||
|
|
"""
|
||
|
|
Create an asyncio task with automatic error logging.
|
||
|
|
|
||
|
|
Unlike bare asyncio.create_task(), this wrapper:
|
||
|
|
- Names the task for easier debugging
|
||
|
|
- Logs any unhandled exception (with full traceback) instead of swallowing it
|
||
|
|
- Keeps a strong reference so the task isn't garbage-collected mid-flight
|
||
|
|
- Auto-cleans the reference set when the task finishes
|
||
|
|
|
||
|
|
Args:
|
||
|
|
coro: The coroutine to schedule.
|
||
|
|
task_name: Human-readable name for log messages.
|
||
|
|
Defaults to the coroutine's __qualname__.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
The created asyncio.Task (tracked internally).
|
||
|
|
"""
|
||
|
|
name = task_name or getattr(coro, "__qualname__", str(coro))
|
||
|
|
|
||
|
|
async def _wrapped():
|
||
|
|
try:
|
||
|
|
await coro
|
||
|
|
except asyncio.CancelledError:
|
||
|
|
logger.debug(f"Task '{name}' was cancelled")
|
||
|
|
raise # re-raise so Task.cancelled() works correctly
|
||
|
|
except Exception:
|
||
|
|
logger.error(f"Background task '{name}' failed", exc_info=True)
|
||
|
|
|
||
|
|
task = asyncio.create_task(_wrapped(), name=name)
|
||
|
|
_active_tasks.add(task)
|
||
|
|
task.add_done_callback(_active_tasks.discard)
|
||
|
|
return task
|