diff --git a/cashu/core/settings.py b/cashu/core/settings.py index 084ccbd..5f999a5 100644 --- a/cashu/core/settings.py +++ b/cashu/core/settings.py @@ -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) diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index d1bf37c..72b9231 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -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 diff --git a/tests/test_mint_init.py b/tests/test_mint_init.py index 514e928..33298f3 100644 --- a/tests/test_mint_init.py +++ b/tests/test_mint_init.py @@ -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