Files
nutshell/cashu/mint/tasks.py
callebtc 6a0a370ba5 Mint: table locks (#566)
* clean up db

* db: table lock

* db.table_with_schema

* fix encrypt.py

* postgres nowait

* add timeout to lock

* melt quote state in db

* kinda working

* kinda working with postgres

* remove dispose

* getting there

* porperly clean up db for tests

* faster tests

* configure connection pooling

* try github with connection pool

* invoice dispatcher does not lock db

* fakewallet: pay_if_regtest waits

* pay fakewallet invoices

* add more

* faster

* slower

* pay_if_regtest async

* do not lock the invoice dispatcher

* test: do I get disk I/O errors if we disable the invoice_callback_dispatcher?

* fix fake so it workss without a callback dispatchert

* test on github

* readd tasks

* refactor

* increase time for lock invoice disatcher

* try avoiding a race

* remove task

* github actions: test regtest with postgres

* mint per module

* no connection pool for testing

* enable pool

* do not resend paid event

* reuse connection

* close db connections

* sessions

* enable debug

* dispose engine

* disable connection pool for tests

* enable connection pool for postgres only

* clean up shutdown routine

* remove wait for lightning fakewallet lightning invoice

* cancel invoice listener tasks on shutdown

* fakewallet conftest: decrease outgoing delay

* delay payment and set postgres only if needed

* disable fail fast for regtest

* clean up regtest.yml

* change order of tests_db.py

* row-specific mint_quote locking

* refactor

* fix lock statement

* refactor swap

* refactor

* remove psycopg2

* add connection string example to .env.example

* remove unnecessary pay

* shorter sleep in test_wallet_subscription_swap
2024-07-08 18:05:57 +02:00

68 lines
2.7 KiB
Python

import asyncio
from typing import List, Mapping
from loguru import logger
from ..core.base import Method, MintQuoteState, Unit
from ..core.db import Database
from ..lightning.base import LightningBackend
from ..mint.crud import LedgerCrud
from .events.events import LedgerEventManager
from .protocols import SupportsBackends, SupportsDb, SupportsEvents
class LedgerTasks(SupportsDb, SupportsBackends, SupportsEvents):
backends: Mapping[Method, Mapping[Unit, LightningBackend]] = {}
db: Database
crud: LedgerCrud
events: LedgerEventManager
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:
while True:
try:
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("Restarting invoice listener...")
await asyncio.sleep(1)
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.state == MintQuoteState.unpaid:
quote.paid = True
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)