Move the per-account INBOX-IDLE + secondary-poll loops out of the supervisor into a self-contained AccountRunner (start/stop/teardown). The startup supervisor now launches one runner per live account. Pure refactor, no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
1.5 KiB
Python
47 lines
1.5 KiB
Python
"""Live-sync supervisor (refactor §4, transitional).
|
|
|
|
Runs inside the sync worker: on startup it launches one :class:`AccountRunner`
|
|
per live account. This step (v2 §9.2) only extracts the per-account loops into a
|
|
runner; account discovery is still startup-only and is replaced by the lease
|
|
claimer in a later step.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
import uuid
|
|
from typing import Any
|
|
|
|
from sqlalchemy import select
|
|
|
|
from app.db import session_scope
|
|
from app.models import Account
|
|
from app.sync.runner import AccountRunner
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def _live_account_ids() -> list[uuid.UUID]:
|
|
async with session_scope() as session:
|
|
return list(await session.scalars(select(Account.id).where(Account.state == "live")))
|
|
|
|
|
|
async def start_supervisor(ctx: dict[str, Any]) -> None:
|
|
"""Launch an AccountRunner per live account (called from the worker on_startup)."""
|
|
runners: dict[uuid.UUID, AccountRunner] = {}
|
|
for account_id in await _live_account_ids():
|
|
runner = AccountRunner(account_id)
|
|
runner.start()
|
|
runners[account_id] = runner
|
|
ctx["runners"] = runners
|
|
logger.info("live supervisor started for %d account(s)", len(runners))
|
|
|
|
|
|
async def stop_supervisor(ctx: dict[str, Any]) -> None:
|
|
"""Stop and tear down all account runners (called from the worker on_shutdown)."""
|
|
runners: dict[uuid.UUID, AccountRunner] = ctx.get("runners", {})
|
|
if runners:
|
|
await asyncio.gather(*(r.stop() for r in runners.values()), return_exceptions=True)
|
|
ctx["runners"] = {}
|