MicroFish/backend/app/services/interviews/lifecycle.py

73 lines
2.2 KiB
Python

"""
Interview lifecycle hook installer (Task 20).
install_hooks(manager) registers two callbacks on a SimulationManager:
- on_ready → spawn T0 longitudinal pre-survey in a background thread
- on_completed → spawn full post-sim batch + synthesis in a background thread
Both hooks are best-effort: failures are logged but never propagate to the
calling thread.
"""
from __future__ import annotations
import threading
from app.utils.logger import get_logger
logger = get_logger(__name__)
def install_hooks(manager) -> None:
"""Attach interview lifecycle callbacks to a SimulationManager.
on_ready → spawn T0 longitudinal in a background thread
on_completed → spawn full post-sim batch in a background thread
Hooks are best-effort; failures only log.
"""
def _on_ready(state) -> None:
sim_id = (
getattr(state, "simulation_id", None)
or getattr(state, "sim_id", None)
or getattr(state, "id", None)
)
if not sim_id:
return
threading.Thread(target=_run_pre, args=(sim_id,), daemon=True).start()
def _on_completed(state) -> None:
sim_id = (
getattr(state, "simulation_id", None)
or getattr(state, "sim_id", None)
or getattr(state, "id", None)
)
if not sim_id:
return
threading.Thread(target=_run_post, args=(sim_id,), daemon=True).start()
manager.register_on_ready(_on_ready)
manager.register_on_completed(_on_completed)
def _run_pre(sim_id: str) -> None:
try:
from app.api.interview import _build_orchestrator
orch = _build_orchestrator(sim_id)
orch.run_pre()
except Exception as e:
logger.warning(f"auto pre-survey failed for {sim_id}: {e!r}")
def _run_post(sim_id: str) -> None:
try:
from app.api.interview import _build_orchestrator
from app.services.interview_synthesizer import InterviewSynthesizer
orch = _build_orchestrator(sim_id)
orch.run_post()
InterviewSynthesizer(store=orch.store).run()
except Exception as e:
logger.warning(f"auto post-survey failed for {sim_id}: {e!r}")