fix(payments): improve YooKassa webhook processing for terminal failures

Refactor the YooKassa webhook handling to better manage terminal payment failures. Introduce checks for payment status based on metadata, ensuring that only terminal failures are committed to the database. Enhance error handling and logging for non-terminal failures, providing clearer responses for retry scenarios. This improves the robustness of payment processing and reduces unnecessary retries.
This commit is contained in:
kavore
2026-02-12 15:23:12 +03:00
parent d39e781203
commit e546ba3515
+37 -13
View File
@@ -690,20 +690,44 @@ async def yookassa_webhook_route(request: web.Request):
yookassa_service, yookassa_service,
lknpd_service) lknpd_service)
if not processed: if not processed:
# process_successful_payment uses False for permanent business failures metadata_for_result = payment_dict_for_processing.get("metadata") or {}
# (e.g. user not found / metadata issues) and may have already updated payment_db_id_raw = metadata_for_result.get("payment_db_id")
# the payment status. Commit the status and ACK the webhook to stop payment_db_id_for_check = None
# indefinite provider retries. if isinstance(payment_db_id_raw, int):
try: payment_db_id_for_check = payment_db_id_raw
await session.commit() elif isinstance(payment_db_id_raw, str) and payment_db_id_raw.isdigit():
except Exception: payment_db_id_for_check = int(payment_db_id_raw)
await session.rollback()
logging.exception( terminal_failure_recorded = False
"Failed to commit failure status for YooKassa payment %s", if payment_db_id_for_check is not None:
payment_dict_for_processing.get("id"), payment_after_processing = await payment_dal.get_payment_by_db_id(
session,
payment_db_id_for_check,
) )
return web.Response(status=503, text="yookassa_processing_failed_retry") terminal_failure_recorded = bool(
return web.Response(status=200, text="ok") payment_after_processing
and isinstance(payment_after_processing.status, str)
and payment_after_processing.status.startswith("failed")
)
if terminal_failure_recorded:
try:
await session.commit()
except Exception:
await session.rollback()
logging.exception(
"Failed to commit failure status for YooKassa payment %s",
payment_dict_for_processing.get("id"),
)
return web.Response(status=503, text="yookassa_processing_failed_retry")
return web.Response(status=200, text="ok")
await session.rollback()
logging.warning(
"YooKassa payment %s processing returned non-terminal failure; responding 503 for retry",
payment_dict_for_processing.get("id"),
)
return web.Response(status=503, text="yookassa_processing_failed_retry")
await session.commit() await session.commit()
else: else:
logging.warning( logging.warning(