""" Async Utilities =============== Safe async patterns for production use. ADR-013: 此模組包含關鍵異步模式,修改前請先讀懂註解! """ import asyncio from collections.abc import Coroutine from typing import Any from src.core.logging import get_logger logger = get_logger("awoooi.async_utils") def fire_and_forget(coro: Coroutine[Any, Any, Any], name: str | None = None) -> asyncio.Task[Any]: """ 安全的 fire-and-forget 模式。 🔴 重要:不使用此函數的 asyncio.create_task() 會吞掉例外! Args: coro: 要執行的協程 name: 任務名稱 (用於日誌) Returns: 已建立的任務 (可忽略) Example: # ✅ 正確用法 fire_and_forget(send_notification(user_id), name="notification") # ❌ 錯誤用法 (例外會被吞掉) asyncio.create_task(send_notification(user_id)) """ task = asyncio.create_task(coro, name=name) def _handle_exception(t: asyncio.Task[Any]) -> None: try: exc = t.exception() if exc is not None: logger.error( "fire_and_forget_exception", task_name=name or "unnamed", error=str(exc), error_type=type(exc).__name__, ) except asyncio.CancelledError: logger.debug("fire_and_forget_cancelled", task_name=name or "unnamed") task.add_done_callback(_handle_exception) return task