Fix routing rule

This commit is contained in:
2026-06-18 14:10:26 +02:00
parent c1633b72d1
commit e70f188633
6 changed files with 667 additions and 177 deletions
+37 -35
View File
@@ -8,8 +8,8 @@ Flusso completo:
- legge le NotificationRule attive del tenant con event_type="new_message"
- applica i filtri opzionali (mailbox_id, direction, pec_type)
- per ogni regola che matcha: crea NotificationLog(status=pending)
- enqueue del job arq dispatch_notification con defer 5s
(per dare tempo al DB di committare prima che il job legga)
- restituisce lista di log_id: il chiamante accoda i job DOPO db.commit()
(evita race condition: il job apre una nuova sessione DB)
4. dispatch_notification(ctx, notification_log_id):
- legge NotificationLog + NotificationChannel dal DB
- controlla circuit breaker
@@ -234,38 +234,49 @@ async def evaluate_and_enqueue_notifications(
message: Message,
mailbox: Mailbox,
db: Any, # AsyncSession evito import circolare
redis_client: Any, # ArqRedis
) -> None:
) -> list[str]:
"""
Valuta le regole di notifica per un messaggio appena salvato e accoda i job.
Valuta le regole di notifica per un messaggio appena salvato,
crea i NotificationLog e restituisce i loro ID.
NON accoda i job arq: il chiamante deve farlo DOPO db.commit()
per evitare race condition (il job dispatch_notification apre una nuova
sessione DB e deve trovare il NotificationLog gia' committato).
Chiamata da sync.py dopo _save_message e index_message.
Non solleva eccezioni: gli errori vengono loggati ma non propagati per
non interrompere il flusso di sincronizzazione IMAP.
Args:
message: messaggio appena salvato nel DB (flush, non commit)
mailbox: casella di appartenenza
db: sessione DB (open, con flush del messaggio)
redis_client: ArqRedis per enqueue_job
message: messaggio appena salvato nel DB (flush, non commit)
mailbox: casella di appartenenza
db: sessione DB (open, con flush del messaggio)
Returns:
Lista di notification_log_id (str) da accodare dopo il commit.
"""
try:
await _do_evaluate_and_enqueue(message, mailbox, db, redis_client)
return await _do_evaluate_and_enqueue(message, mailbox, db)
except Exception as exc:
logger.error(
f"Errore evaluate_and_enqueue_notifications per messaggio "
f"{message.id}: {exc}",
exc_info=True,
)
return []
async def _do_evaluate_and_enqueue(
message: Message,
mailbox: Mailbox,
db: Any,
redis_client: Any,
) -> None:
"""Logica interna puo' sollevare eccezioni."""
) -> list[str]:
"""
Logica interna puo' sollevare eccezioni.
Crea i NotificationLog e restituisce i loro ID.
NON accoda job arq: il chiamante lo fa dopo db.commit().
"""
# Carica regole attive per questo tenant con event_type = "new_message"
rules_result = await db.execute(
@@ -280,9 +291,9 @@ async def _do_evaluate_and_enqueue(
rules: list[NotificationRule] = list(rules_result.scalars().all())
if not rules:
return
return []
enqueued_count = 0
log_ids: list[str] = []
for rule in rules:
channel = rule.channel
@@ -336,31 +347,22 @@ async def _do_evaluate_and_enqueue(
db.add(log)
await db.flush() # ottieni log.id
# Enqueue arq job con defer 5s per attendere il commit DB
try:
await redis_client.enqueue_job(
"dispatch_notification",
str(log.id),
_defer_by=timedelta(seconds=5),
)
enqueued_count += 1
logger.info(
f"[notify] Enqueued dispatch_notification per regola "
f"{rule.name!r} -> canale {channel.name!r} "
f"(log_id={log.id})"
)
except Exception as e:
logger.error(
f"[notify] Impossibile enqueue dispatch_notification "
f"per log {log.id}: {e}"
)
# Raccoglie log_id: il job viene accodato dal chiamante DOPO db.commit()
log_ids.append(str(log.id))
logger.info(
f"[notify] NotificationLog creato per regola "
f"{rule.name!r} -> canale {channel.name!r} "
f"(log_id={log.id})"
)
if enqueued_count > 0:
if log_ids:
logger.info(
f"[notify] Messaggio {message.id}: "
f"{enqueued_count} notifiche accodate"
f"{len(log_ids)} notifiche pronte per dispatch"
)
return log_ids
# ─── Job arq principale ───────────────────────────────────────────────────────