Cjbeery24/mint copy: Invoice checker background tasks (#722)

* #616: Removed blocking call from ledger startup. Instead added it to a background task that repeats every hour.

* make task interval configurable, remember task and cancel it on shutdown

* comments

* add sleep to tests because the background task is async

---------

Co-authored-by: Caleb Beery <cjbeery@gmail.com>
This commit is contained in:
callebtc
2025-04-10 21:25:18 +07:00
committed by GitHub
parent 76e2601efd
commit e1220d2329
3 changed files with 34 additions and 1 deletions

View File

@@ -64,6 +64,13 @@ class MintSettings(CashuSettings):
mint_input_fee_ppk: int = Field(default=0)
mint_disable_melt_on_error: bool = Field(default=False)
mint_regular_tasks_interval_seconds: int = Field(
default=3600,
gt=0,
title="Regular tasks interval",
description="Interval (in seconds) for running regular tasks like the invoice checker.",
)
class MintDeprecationFlags(MintSettings):
mint_inactivate_base64_keysets: bool = Field(default=False)

View File

@@ -95,6 +95,7 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
self.db_read: DbReadHelper
self.locks: Dict[str, asyncio.Lock] = {} # holds multiprocessing locks
self.invoice_listener_tasks: List[asyncio.Task] = []
self.regular_tasks: List[asyncio.Task] = []
if not seed:
raise Exception("seed not set")
@@ -132,7 +133,7 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
async def startup_ledger(self) -> None:
await self._startup_keysets()
await self._check_backends()
await self._check_pending_proofs_and_melt_quotes()
self.regular_tasks.append(asyncio.create_task(self._run_regular_tasks()))
self.invoice_listener_tasks = await self.dispatch_listeners()
async def _startup_keysets(self) -> None:
@@ -140,6 +141,14 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
for derivation_path in settings.mint_derivation_path_list:
await self.activate_keyset(derivation_path=derivation_path)
async def _run_regular_tasks(self) -> None:
try:
await self._check_pending_proofs_and_melt_quotes()
await asyncio.sleep(settings.mint_regular_tasks_interval_seconds)
except Exception as e:
logger.error(f"Ledger regular task failed: {e}")
await asyncio.sleep(60)
async def _check_backends(self) -> None:
for method in self.backends:
for unit in self.backends[method]:
@@ -160,9 +169,14 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerTasks, LedgerFe
logger.info(f"Data dir: {settings.cashu_dir}")
async def shutdown_ledger(self) -> None:
logger.debug("Disconnecting from database")
await self.db.engine.dispose()
logger.debug("Shutting down invoice listeners")
for task in self.invoice_listener_tasks:
task.cancel()
logger.debug("Shutting down regular tasks")
for task in self.regular_tasks:
task.cancel()
async def _check_pending_proofs_and_melt_quotes(self):
"""Startup routine that checks all pending melt quotes and either invalidates

View File

@@ -178,6 +178,9 @@ async def test_startup_fakewallet_pending_quote_success(ledger: Ledger):
# run startup routinge
await ledger.startup_ledger()
# we need to sleep because the startup routine for checking the invoices is async
await asyncio.sleep(1)
# expect that no pending tokens are in db anymore
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
@@ -204,6 +207,9 @@ async def test_startup_fakewallet_pending_quote_failure(ledger: Ledger):
# run startup routinge
await ledger.startup_ledger()
# we need to sleep because the startup routine for checking the invoices is async
await asyncio.sleep(1)
# expect that no pending tokens are in db anymore
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
@@ -225,6 +231,9 @@ async def test_startup_fakewallet_pending_quote_pending(ledger: Ledger):
# run startup routinge
await ledger.startup_ledger()
# we need to sleep because the startup routine for checking the invoices is async
await asyncio.sleep(1)
# expect that melt quote is still pending
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db
@@ -247,6 +256,9 @@ async def test_startup_fakewallet_pending_quote_unknown(ledger: Ledger):
# run startup routinge
await ledger.startup_ledger()
# we need to sleep because the startup routine for checking the invoices is async
await asyncio.sleep(1)
# expect that melt quote is still pending
melt_quotes = await ledger.crud.get_all_melt_quotes_from_pending_proofs(
db=ledger.db