# backend/app/worker/main.py — 잡 등록 진입 (phase-7 소유, phase-13/14 가 잡 추가) # WORKER_ENABLED=false(기본)면 스케줄러 미가동 — routers/worker.py 의 수동 트리거로 동작. from sqlmodel import Session from ..db import engine def _wrap(fn, **kw): def _job(): with Session(engine) as s: fn(s, **kw) return _job def register(scheduler) -> None: """APScheduler 등 스케줄러가 주어질 때만 잡을 등록(있을 때). 없으면 수동 트리거.""" from .jobs.digest import run_digest from .jobs.proactive import run_proactive from .jobs.weekly_review import run_weekly_review scheduler.add_job( _wrap(run_proactive), "interval", minutes=30, id="proactive", replace_existing=True ) for t in ["09:00", "13:00", "18:30"]: h, m = t.split(":") scheduler.add_job( _wrap(run_digest, slot=t), "cron", hour=int(h), minute=int(m), id=f"digest-{t}", replace_existing=True, ) scheduler.add_job( _wrap(run_weekly_review), "cron", day_of_week="sun", hour=20, id="weekly_review", replace_existing=True, ) # phase-13 sync_jobs.register(scheduler) 도 같은 진입에서 호출 가능 try: from .sync_jobs import register as register_sync register_sync(scheduler) except Exception: pass def register_event_subscribers(bus, session_factory) -> None: """런타임 event_bus 구독: approval.executed → 승인된 메일 결재 발송(phase-16).""" from sqlmodel import select from ..connectors.mail.outbound import send_outbound from ..models import Approval, OutboundMail def _on_approval_executed(ev): # phase-16: 승인된 메일 결재 → 실제 발송(real) 또는 mock(Sent) approval_id = (ev.payload or {}).get("approval_id") if not approval_id: return with session_factory() as s: appr = s.get(Approval, approval_id) if not appr or appr.source != "mail": return ob = s.exec( select(OutboundMail).where( OutboundMail.approval_id == approval_id, OutboundMail.status == "pending", ) ).first() if ob: send_outbound(s, ob) bus.subscribe("approval.executed", _on_approval_executed)