From 5f1cfc0e37f1ed6786cfeed236900ba928c0d2bb Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Wed, 26 Nov 2025 19:53:10 +0200 Subject: [PATCH] [perf] send payment notifications in background (#3588) --- lnbits/core/services/notifications.py | 8 ++++++++ lnbits/core/services/payments.py | 6 +++--- tests/unit/test_pay_invoice.py | 10 +++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lnbits/core/services/notifications.py b/lnbits/core/services/notifications.py index 01cf2a40..8860fbd6 100644 --- a/lnbits/core/services/notifications.py +++ b/lnbits/core/services/notifications.py @@ -1,6 +1,7 @@ import asyncio import json import smtplib +from asyncio.tasks import create_task from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from http import HTTPStatus @@ -286,6 +287,13 @@ async def send_payment_notification(wallet: Wallet, payment: Payment): logger.error(f"Error dispatching webhook: {e!s}") +def send_payment_notification_in_background(wallet: Wallet, payment: Payment): + try: + create_task(send_payment_notification(wallet, payment)) + except Exception as e: + logger.warning(f"Error sending payment notification: {e}") + + async def send_ws_payment_notification(wallet: Wallet, payment: Payment): # TODO: websocket message should be a clean payment model # await websocket_manager.send(wallet.inkey, payment.json()) diff --git a/lnbits/core/services/payments.py b/lnbits/core/services/payments.py index e9060ca4..ae029948 100644 --- a/lnbits/core/services/payments.py +++ b/lnbits/core/services/payments.py @@ -47,7 +47,7 @@ from ..models import ( PaymentState, Wallet, ) -from .notifications import send_payment_notification +from .notifications import send_payment_notification_in_background payment_lock = asyncio.Lock() wallets_payments_lock: dict[str, asyncio.Lock] = {} @@ -741,7 +741,7 @@ async def _pay_internal_invoice( await update_payment(internal_payment, conn=conn) logger.success(f"internal payment successful {internal_payment.checking_id}") - await send_payment_notification(wallet, payment) + send_payment_notification_in_background(wallet, payment) # notify receiver asynchronously from lnbits.tasks import internal_invoice_queue @@ -814,7 +814,7 @@ async def _pay_external_invoice( payment = await update_payment_success_status( payment, payment_response, conn=conn ) - await send_payment_notification(wallet, payment) + send_payment_notification_in_background(wallet, payment) logger.success(f"payment successful {payment_response.checking_id}") payment.checking_id = payment_response.checking_id diff --git a/tests/unit/test_pay_invoice.py b/tests/unit/test_pay_invoice.py index f7aa3e67..961c4ddf 100644 --- a/tests/unit/test_pay_invoice.py +++ b/tests/unit/test_pay_invoice.py @@ -298,7 +298,7 @@ async def test_retry_failed_invoice( assert external_invoice.payment_request ws_notification = mocker.patch( - "lnbits.core.services.payments.send_payment_notification", + "lnbits.core.services.payments.send_payment_notification_in_background", AsyncMock(return_value=None), ) @@ -378,7 +378,7 @@ async def test_pay_external_invoice_pending( AsyncMock(return_value=payment_reponse_pending), ) ws_notification = mocker.patch( - "lnbits.core.services.payments.send_payment_notification", + "lnbits.core.services.payments.send_payment_notification_in_background", AsyncMock(return_value=None), ) wallet = await get_wallet(from_wallet.id) @@ -428,7 +428,7 @@ async def test_retry_pay_external_invoice_pending( AsyncMock(return_value=payment_reponse_pending), ) ws_notification = mocker.patch( - "lnbits.core.services.payments.send_payment_notification", + "lnbits.core.services.payments.send_payment_notification_in_background", AsyncMock(return_value=None), ) wallet = await get_wallet(from_wallet.id) @@ -474,7 +474,7 @@ async def test_pay_external_invoice_success( AsyncMock(return_value=payment_reponse_pending), ) ws_notification = mocker.patch( - "lnbits.core.services.payments.send_payment_notification", + "lnbits.core.services.payments.send_payment_notification_in_background", AsyncMock(return_value=None), ) wallet = await get_wallet(from_wallet.id) @@ -520,7 +520,7 @@ async def test_retry_pay_success( AsyncMock(return_value=payment_reponse_pending), ) ws_notification = mocker.patch( - "lnbits.core.services.payments.send_payment_notification", + "lnbits.core.services.payments.send_payment_notification_in_background", AsyncMock(return_value=None), ) wallet = await get_wallet(from_wallet.id)