refactor: add status column to apipayments (#2537)
* refactor: add status column to apipayments keep track of the payment status with an enum and persist it as string to db. `pending`, `success`, `failed`. - database migration - remove deleting of payments, failed payments stay
This commit is contained in:
+39
-32
@@ -11,11 +11,13 @@ from py_vapid import Vapid
|
||||
from pywebpush import WebPushException, webpush
|
||||
|
||||
from lnbits.core.crud import (
|
||||
delete_expired_invoices,
|
||||
delete_webpush_subscriptions,
|
||||
get_payments,
|
||||
get_standalone_payment,
|
||||
update_payment_details,
|
||||
update_payment_status,
|
||||
)
|
||||
from lnbits.core.models import PaymentState
|
||||
from lnbits.settings import settings
|
||||
from lnbits.wallets import get_funding_source
|
||||
|
||||
@@ -131,45 +133,41 @@ async def check_pending_payments():
|
||||
the backend and also to delete expired invoices. Incoming payments will be
|
||||
checked only once, outgoing pending payments will be checked regularly.
|
||||
"""
|
||||
outgoing = True
|
||||
incoming = True
|
||||
|
||||
while settings.lnbits_running:
|
||||
logger.info(
|
||||
f"Task: checking all pending payments (incoming={incoming},"
|
||||
f" outgoing={outgoing}) of last 15 days"
|
||||
)
|
||||
start_time = time.time()
|
||||
pending_payments = await get_payments(
|
||||
since=(int(time.time()) - 60 * 60 * 24 * 15), # 15 days ago
|
||||
complete=False,
|
||||
pending=True,
|
||||
outgoing=outgoing,
|
||||
incoming=incoming,
|
||||
exclude_uncheckable=True,
|
||||
)
|
||||
for payment in pending_payments:
|
||||
await payment.check_status()
|
||||
await asyncio.sleep(0.01) # to avoid complete blocking
|
||||
|
||||
logger.info(
|
||||
f"Task: pending check finished for {len(pending_payments)} payments"
|
||||
f" (took {time.time() - start_time:0.3f} s)"
|
||||
)
|
||||
# we delete expired invoices once upon the first pending check
|
||||
if incoming:
|
||||
logger.debug("Task: deleting all expired invoices")
|
||||
start_time = time.time()
|
||||
await delete_expired_invoices()
|
||||
count = len(pending_payments)
|
||||
if count > 0:
|
||||
logger.info(f"Task: checking {count} pending payments of last 15 days...")
|
||||
for i, payment in enumerate(pending_payments):
|
||||
status = await payment.check_status()
|
||||
prefix = f"payment ({i+1} / {count})"
|
||||
if status.failed:
|
||||
await update_payment_status(
|
||||
payment.checking_id, status=PaymentState.FAILED
|
||||
)
|
||||
logger.debug(f"{prefix} failed {payment.checking_id}")
|
||||
elif status.success:
|
||||
await update_payment_details(
|
||||
checking_id=payment.checking_id,
|
||||
fee=status.fee_msat,
|
||||
preimage=status.preimage,
|
||||
status=PaymentState.SUCCESS,
|
||||
)
|
||||
logger.debug(f"{prefix} success {payment.checking_id}")
|
||||
else:
|
||||
logger.debug(f"{prefix} pending {payment.checking_id}")
|
||||
await asyncio.sleep(0.01) # to avoid complete blocking
|
||||
logger.info(
|
||||
"Task: expired invoice deletion finished (took"
|
||||
f" {time.time() - start_time:0.3f} s)"
|
||||
f"Task: pending check finished for {count} payments"
|
||||
f" (took {time.time() - start_time:0.3f} s)"
|
||||
)
|
||||
|
||||
# after the first check we will only check outgoing, not incoming
|
||||
# that will be handled by the global invoice listeners, hopefully
|
||||
incoming = False
|
||||
|
||||
await asyncio.sleep(60 * 30) # every 30 minutes
|
||||
|
||||
|
||||
@@ -183,7 +181,13 @@ async def invoice_callback_dispatcher(checking_id: str):
|
||||
logger.trace(
|
||||
f"invoice listeners: sending invoice callback for payment {checking_id}"
|
||||
)
|
||||
await payment.check_status()
|
||||
status = await payment.check_status()
|
||||
await update_payment_details(
|
||||
checking_id=payment.checking_id,
|
||||
fee=status.fee_msat,
|
||||
preimage=status.preimage,
|
||||
status=PaymentState.SUCCESS,
|
||||
)
|
||||
for name, send_chan in invoice_listeners.items():
|
||||
logger.trace(f"invoice listeners: sending to `{name}`")
|
||||
await send_chan.put(payment)
|
||||
@@ -204,8 +208,11 @@ async def send_push_notification(subscription, title, body, url=""):
|
||||
{"aud": "", "sub": "mailto:alan@lnbits.com"},
|
||||
)
|
||||
except WebPushException as e:
|
||||
if e.response.status_code == HTTPStatus.GONE:
|
||||
if e.response and e.response.status_code == HTTPStatus.GONE:
|
||||
# cleanup unsubscribed or expired push subscriptions
|
||||
await delete_webpush_subscriptions(subscription.endpoint)
|
||||
else:
|
||||
logger.error(f"failed sending push notification: {e.response.text}")
|
||||
logger.error(
|
||||
f"failed sending push notification: "
|
||||
f"{e.response.text if e.response else e}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user