""" Job arq: sync_mailbox – trigger manuale per forzare la sincronizzazione di una casella. Questo job viene usato per: - Forzare una sync immediata dopo la creazione di una nuova casella - Resync manuale da parte dell'admin - Retry dopo un errore (called dal pool monitor) Non sostituisce il loop IMAP continuo (IMAPConnection); è un one-shot job. """ import logging from typing import Any from app.database import AsyncSessionLocal from app.imap.reconnect import ExponentialBackoff from app.imap.sync import sync_new_messages from app.models import Mailbox logger = logging.getLogger(__name__) async def sync_mailbox(ctx: dict[str, Any], mailbox_id: str) -> dict: """ Job arq: sincronizza una singola casella PEC. Args: ctx: contesto arq (contiene redis, pool reference) mailbox_id: UUID della casella da sincronizzare Returns: dict con risultato del job """ redis_client = ctx.get("redis") async with AsyncSessionLocal() as db: mailbox = await db.get(Mailbox, mailbox_id) if not mailbox: return {"status": "error", "message": f"Mailbox {mailbox_id} non trovata"} if mailbox.status not in ("active", "error"): return { "status": "skipped", "message": f"Mailbox status={mailbox.status}, skip", } from app.imap.connection import IMAPConnection creds = IMAPConnection._decrypt_creds(mailbox) try: from app.imap.connection import IMAPConnection conn = IMAPConnection(mailbox_id=mailbox_id, redis_client=redis_client) client = await conn._connect(creds) n = await sync_new_messages(client, mailbox, db, redis_client) try: await client.logout() except Exception: pass return { "status": "ok", "mailbox": mailbox.email_address, "new_messages": n, } except Exception as e: logger.error(f"[sync_mailbox] {mailbox_id} errore: {e}", exc_info=True) return { "status": "error", "mailbox": mailbox.email_address, "message": str(e), }