Skip to content

Commit aef5e8d

Browse files
Marcello AlarconMarcello Alarcon
authored andcommitted
fix(wpp-retry): restringe except IntegrityError nos dois pontos do triggers
Endereça review do Sourcery em PR evolution-foundation#80 (Comment 1) e estende a mesma proteção para o endpoint de replay (não citado pelo Sourcery, mas contém o mesmo bug latente — `except IntegrityError` genérico). Dois pontos corrigidos em dashboard/backend/routes/triggers.py: 1. `webhook_receiver` (linha ~389): mesmo bug do PR evolution-foundation#78. Capturava qualquer IntegrityError e respondia 200 OK silencioso. Agora só absorve se a mensagem do driver menciona `uq_trigger_idem` ou `idempotency_key` e `idem_key` está definido. Caso contrário, loga erro completo e re-raise. 2. Endpoint `/triggers/executions/<id>/replay` (linha ~476): cria nova execution reusando `ex.idempotency_key`. Tinha o mesmo catch genérico, mascarando outros IntegrityError como "idempotent_skip". Aplicada a mesma proteção, usando `ex.idempotency_key` no check. Sem teste dedicado pra esse path nessa branch — sintaxe validada com py_compile.
1 parent 257179b commit aef5e8d

1 file changed

Lines changed: 32 additions & 4 deletions

File tree

dashboard/backend/routes/triggers.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -386,11 +386,26 @@ def webhook_receiver(trigger_id):
386386
db.session.add(execution)
387387
try:
388388
db.session.commit()
389-
except IntegrityError:
389+
except IntegrityError as exc:
390+
# Restringe o catch à violação do índice de idempotência
391+
# (uq_trigger_idem). Qualquer outro IntegrityError (NOT NULL, FK,
392+
# outros uniques) é um problema real e precisa propagar — caso
393+
# contrário viraria 200 OK silencioso e mascararia bug de schema.
394+
db.session.rollback()
395+
err_text = str(getattr(exc, "orig", exc)).lower()
396+
is_idem_violation = (
397+
idem_key is not None
398+
and ("uq_trigger_idem" in err_text or "idempotency_key" in err_text)
399+
)
400+
if not is_idem_violation:
401+
current_app.logger.error(
402+
f"evt=integrity_error_unexpected trigger_id={trigger.id} "
403+
f"key={idem_key} err={err_text!r}"
404+
)
405+
raise
390406
# Race condition: two simultaneous POSTs with same idempotency_key;
391407
# the DB partial unique index rejected the second INSERT.
392408
# Silent dedup — return 200 OK (F6) without re-executing.
393-
db.session.rollback()
394409
current_app.logger.info(
395410
f"evt=idempotent_replay_race trigger_id={trigger.id} key={idem_key}"
396411
)
@@ -473,9 +488,22 @@ def replay_execution(exec_id: int):
473488

474489
try:
475490
db.session.commit()
476-
except IntegrityError:
477-
# idempotency_key already has a successful execution — silent ok
491+
except IntegrityError as exc:
492+
# Mesma proteção do webhook_receiver: só absorve a violação se for
493+
# do índice de idempotência. Outros IntegrityError (NOT NULL, FK,
494+
# outros uniques) precisam propagar para não mascarar bugs reais.
478495
db.session.rollback()
496+
err_text = str(getattr(exc, "orig", exc)).lower()
497+
is_idem_violation = (
498+
ex.idempotency_key is not None
499+
and ("uq_trigger_idem" in err_text or "idempotency_key" in err_text)
500+
)
501+
if not is_idem_violation:
502+
current_app.logger.error(
503+
f"evt=integrity_error_unexpected_replay exec_id={ex.id} "
504+
f"key={ex.idempotency_key} err={err_text!r}"
505+
)
506+
raise
479507
return jsonify({"status": "ok", "note": "idempotent_skip"}), 200
480508

481509
new_execution_id = new_ex.id

0 commit comments

Comments
 (0)