mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-06-29 16:12:06 -04:00
Two background tasks scheduled on every chat completion in routes/chat_helpers.py — the memory/skill extraction dispatch and the session auto-namer — are created via bare asyncio.create_task(...). asyncio only holds a weak reference to the outer task, so the GC can collect it mid-execution and the work silently never runs. Add a module-private _BG_TASKS set and a _spawn_bg() helper that mirrors WebhookManager._spawn_tracked (the pattern #3964 / #4336 established for the webhook emitters two lines apart in the same function). Route both call sites through it so the lifecycle owner is explicit. Adds an AST-level guard test that fails on any bare asyncio.create_task(...) statement in routes/chat_helpers.py to prevent a regression — same shape as test_webhook_emitters_use_manager.py from #4336. The same bare pattern exists in routes/email_routes.py and routes/cookbook_routes.py; left out of this PR per CONTRIBUTING.md's "one fix per PR" and tracked in #4443's "Additional Information" for a follow-up.
This commit is contained in:
+18
-2
@@ -23,6 +23,22 @@ from fastapi import HTTPException
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Strong references to in-flight fire-and-forget tasks scheduled from this
|
||||
# module. asyncio only keeps weak references to tasks created via
|
||||
# create_task, so without this the GC can collect a task mid-execution and
|
||||
# the background work (extraction, auto-naming) silently never runs.
|
||||
# Mirrors WebhookManager._spawn_tracked from src/webhook_manager.py.
|
||||
_BG_TASKS: set[asyncio.Task] = set()
|
||||
|
||||
|
||||
def _spawn_bg(coro) -> asyncio.Task:
|
||||
"""Schedule a background task and hold a strong reference until it finishes."""
|
||||
task = asyncio.create_task(coro)
|
||||
_BG_TASKS.add(task)
|
||||
task.add_done_callback(_BG_TASKS.discard)
|
||||
return task
|
||||
|
||||
|
||||
# ── Data containers ────────────────────────────────────────────────────── #
|
||||
|
||||
@dataclass
|
||||
@@ -1105,7 +1121,7 @@ def run_post_response_tasks(
|
||||
)))
|
||||
|
||||
if _extraction_jobs:
|
||||
asyncio.create_task(_run_extraction_jobs_sequentially(session_id, _extraction_jobs))
|
||||
_spawn_bg(_run_extraction_jobs_sequentially(session_id, _extraction_jobs))
|
||||
|
||||
# Token accumulation
|
||||
if last_metrics:
|
||||
@@ -1120,4 +1136,4 @@ def run_post_response_tasks(
|
||||
|
||||
# Auto-name
|
||||
if needs_auto_name(sess.name):
|
||||
asyncio.create_task(auto_name_session(session_manager, sess))
|
||||
_spawn_bg(auto_name_session(session_manager, sess))
|
||||
|
||||
Reference in New Issue
Block a user