Files
nutshell/cashu/mint/tasks.py
2025-11-22 17:48:36 +01:00

70 lines
2.9 KiB
Python

import asyncio
from typing import List
from loguru import logger
from ..core.base import MintQuoteState
from ..core.settings import settings
from ..lightning.base import LightningBackend
from .protocols import SupportsBackends, SupportsDb, SupportsEvents
class LedgerTasks(SupportsDb, SupportsBackends, SupportsEvents):
async def dispatch_listeners(self) -> List[asyncio.Task]:
tasks = []
for method, unitbackends in self.backends.items():
for unit, backend in unitbackends.items():
logger.debug(
f"Dispatching backend invoice listener for {method} {unit} {backend.__class__.__name__}"
)
tasks.append(asyncio.create_task(self.invoice_listener(backend)))
return tasks
async def invoice_listener(self, backend: LightningBackend) -> None:
if backend.supports_incoming_payment_stream:
retry_delay = settings.mint_retry_exponential_backoff_base_delay
max_retry_delay = settings.mint_retry_exponential_backoff_max_delay
while True:
try:
# Reset retry delay on successful connection to backend stream
retry_delay = settings.mint_retry_exponential_backoff_base_delay
async for checking_id in backend.paid_invoices_stream():
await self.invoice_callback_dispatcher(checking_id)
except Exception as e:
logger.error(f"Error in invoice listener: {e}")
logger.info(
f"Restarting invoice listener in {retry_delay} seconds..."
)
await asyncio.sleep(retry_delay)
# Exponential backoff
retry_delay = min(retry_delay * 2, max_retry_delay)
async def invoice_callback_dispatcher(self, checking_id: str) -> None:
logger.debug(f"Invoice callback dispatcher: {checking_id}")
async with self.db.get_connection(
lock_table="mint_quotes",
lock_select_statement=f"checking_id='{checking_id}'",
lock_timeout=5,
) as conn:
quote = await self.crud.get_mint_quote(
checking_id=checking_id, db=self.db, conn=conn
)
if not quote:
logger.error(f"Quote not found for {checking_id}")
return
logger.trace(
f"Invoice callback dispatcher: quote {quote} trying to set as {MintQuoteState.paid}"
)
# set the quote as paid
if quote.unpaid:
quote.state = MintQuoteState.paid
await self.crud.update_mint_quote(quote=quote, db=self.db, conn=conn)
logger.trace(
f"Quote {quote.quote} with {MintQuoteState.unpaid} set as {quote.state.value}"
)
await self.events.submit(quote)