From 4ac30116a9775d5bd8e12927a6735a9d326ee632 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Mon, 22 Apr 2024 12:33:53 +0300 Subject: [PATCH] feat: add `settings.lnbits_running ` (#2450) * feat: add `settings.lnbits_runing ` --- lnbits/app.py | 9 +++++++-- lnbits/core/tasks.py | 6 +++--- lnbits/core/views/payment_api.py | 2 +- lnbits/core/views/websocket_api.py | 4 +++- lnbits/settings.py | 6 ++++++ lnbits/tasks.py | 4 ++-- lnbits/utils/cache.py | 4 +++- lnbits/wallets/alby.py | 2 +- lnbits/wallets/cliche.py | 4 ++-- lnbits/wallets/corelightning.py | 2 +- lnbits/wallets/corelightningrest.py | 2 +- lnbits/wallets/eclair.py | 4 ++-- lnbits/wallets/fake.py | 2 +- lnbits/wallets/lnbits.py | 2 +- lnbits/wallets/lndgrpc.py | 2 +- lnbits/wallets/lndrest.py | 2 +- lnbits/wallets/lnpay.py | 2 +- lnbits/wallets/lntips.py | 2 +- lnbits/wallets/opennode.py | 2 +- lnbits/wallets/spark.py | 2 +- lnbits/wallets/zbd.py | 2 +- 21 files changed, 41 insertions(+), 26 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index 1923e3234..dd8feca9c 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -69,6 +69,8 @@ from .tasks import ( async def startup(app: FastAPI): + settings.lnbits_running = True + # wait till migration is done await migrate_databases() @@ -104,6 +106,9 @@ async def startup(app: FastAPI): async def shutdown(): + logger.warning("LNbits shutting down...") + settings.lnbits_running = False + # shutdown event cancel_all_tasks() @@ -181,7 +186,7 @@ async def check_funding_source() -> None: max_retries = settings.funding_source_max_retries retry_counter = 0 - while True: + while settings.lnbits_running: try: logger.info(f"Connecting to backend {funding_source.__class__.__name__}...") error_message, balance = await funding_source.status() @@ -412,7 +417,7 @@ def initialize_server_logger(): serverlog_queue = asyncio.Queue() async def update_websocket_serverlog(): - while True: + while settings.lnbits_running: msg = await serverlog_queue.get() await websocket_updater(super_user_hash, msg) diff --git a/lnbits/core/tasks.py b/lnbits/core/tasks.py index 703cd2f91..e0c9c99a4 100644 --- a/lnbits/core/tasks.py +++ b/lnbits/core/tasks.py @@ -26,7 +26,7 @@ async def killswitch_task(): killswitch will check lnbits-status repository for a signal from LNbits and will switch to VoidWallet if the killswitch is triggered. """ - while True: + while settings.lnbits_running: funding_source = get_funding_source() if ( settings.lnbits_killswitch @@ -56,7 +56,7 @@ async def watchdog_task(): Registers a watchdog which will check lnbits balance and nodebalance and will switch to VoidWallet if the watchdog delta is reached. """ - while True: + while settings.lnbits_running: funding_source = get_funding_source() if ( settings.lnbits_watchdog @@ -77,7 +77,7 @@ async def wait_for_paid_invoices(invoice_paid_queue: asyncio.Queue): """ This worker dispatches events to all extensions and dispatches webhooks. """ - while True: + while settings.lnbits_running: payment = await invoice_paid_queue.get() logger.trace("received invoice paid event") # dispatch api_invoice_listeners diff --git a/lnbits/core/views/payment_api.py b/lnbits/core/views/payment_api.py index fb3404195..44e5e0d37 100644 --- a/lnbits/core/views/payment_api.py +++ b/lnbits/core/views/payment_api.py @@ -379,7 +379,7 @@ async def subscribe_wallet_invoices(request: Request, wallet: Wallet): api_invoice_listeners[uid] = payment_queue try: - while True: + while settings.lnbits_running: if await request.is_disconnected(): await request.close() break diff --git a/lnbits/core/views/websocket_api.py b/lnbits/core/views/websocket_api.py index 668ce09e0..e0ea53924 100644 --- a/lnbits/core/views/websocket_api.py +++ b/lnbits/core/views/websocket_api.py @@ -4,6 +4,8 @@ from fastapi import ( WebSocketDisconnect, ) +from lnbits.settings import settings + from ..services import ( websocket_manager, websocket_updater, @@ -16,7 +18,7 @@ websocket_router = APIRouter(prefix="/api/v1/ws", tags=["Websocket"]) async def websocket_connect(websocket: WebSocket, item_id: str): await websocket_manager.connect(websocket, item_id) try: - while True: + while settings.lnbits_running: await websocket.receive_text() except WebSocketDisconnect: websocket_manager.disconnect(websocket) diff --git a/lnbits/settings.py b/lnbits/settings.py index a55a37a29..f93acb501 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -423,6 +423,12 @@ class TransientSettings(InstalledExtensionsSettings): # - are cleared on server restart first_install: bool = Field(default=False) + # Indicates that the server should continue to run. + # When set to false it indicates that the shutdown procedure is ongoing. + # If false no new tasks, threads, etc should be started. + # Long running while loops should use this flag instead of `while True:` + lnbits_running: bool = Field(default=True) + @classmethod def readonly_fields(cls): return [f for f in inspect.signature(cls).parameters if not f.startswith("_")] diff --git a/lnbits/tasks.py b/lnbits/tasks.py index b52abfafe..f3a2a4942 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -106,7 +106,7 @@ async def internal_invoice_listener(): Called by the app startup sequence. """ - while True: + while settings.lnbits_running: checking_id = await internal_invoice_queue.get() logger.info("> got internal payment notification", checking_id) create_task(invoice_callback_dispatcher(checking_id)) @@ -134,7 +134,7 @@ async def check_pending_payments(): outgoing = True incoming = True - while True: + while settings.lnbits_running: logger.info( f"Task: checking all pending payments (incoming={incoming}," f" outgoing={outgoing}) of last 15 days" diff --git a/lnbits/utils/cache.py b/lnbits/utils/cache.py index a5f54958c..8abcfbbef 100644 --- a/lnbits/utils/cache.py +++ b/lnbits/utils/cache.py @@ -6,6 +6,8 @@ from typing import Any, NamedTuple, Optional from loguru import logger +from lnbits.settings import settings + class Cached(NamedTuple): value: Any @@ -52,7 +54,7 @@ class Cache: return value async def invalidate_forever(self): - while True: + while settings.lnbits_running: try: await asyncio.sleep(self.interval) ts = time() diff --git a/lnbits/wallets/alby.py b/lnbits/wallets/alby.py index 69a9509b0..3a7bc6d26 100644 --- a/lnbits/wallets/alby.py +++ b/lnbits/wallets/alby.py @@ -184,6 +184,6 @@ class AlbyWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) - while True: + while settings.lnbits_running: value = await self.queue.get() yield value diff --git a/lnbits/wallets/cliche.py b/lnbits/wallets/cliche.py index d7bd99d46..e54622c13 100644 --- a/lnbits/wallets/cliche.py +++ b/lnbits/wallets/cliche.py @@ -166,10 +166,10 @@ class ClicheWallet(Wallet): ) async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: try: ws = create_connection(self.endpoint) - while True: + while settings.lnbits_running: r = ws.recv() data = json.loads(r) print(data) diff --git a/lnbits/wallets/corelightning.py b/lnbits/wallets/corelightning.py index 430d2c2f2..a4736fb98 100644 --- a/lnbits/wallets/corelightning.py +++ b/lnbits/wallets/corelightning.py @@ -232,7 +232,7 @@ class CoreLightningWallet(Wallet): return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: try: paid = await run_sync( lambda: self.ln.waitanyinvoice(self.last_pay_index, timeout=2) diff --git a/lnbits/wallets/corelightningrest.py b/lnbits/wallets/corelightningrest.py index 8a173b49c..f5031fc5c 100644 --- a/lnbits/wallets/corelightningrest.py +++ b/lnbits/wallets/corelightningrest.py @@ -256,7 +256,7 @@ class CoreLightningRestWallet(Wallet): return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: try: url = f"{self.url}/v1/invoice/waitAnyInvoice/{self.last_pay_index}" async with self.client.stream("GET", url, timeout=None) as r: diff --git a/lnbits/wallets/eclair.py b/lnbits/wallets/eclair.py index e119f571d..3f612c6c3 100644 --- a/lnbits/wallets/eclair.py +++ b/lnbits/wallets/eclair.py @@ -215,13 +215,13 @@ class EclairWallet(Wallet): return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: try: async with connect( self.ws_url, extra_headers=[("Authorization", self.headers["Authorization"])], ) as ws: - while True: + while settings.lnbits_running: message = await ws.recv() message_json = json.loads(message) diff --git a/lnbits/wallets/fake.py b/lnbits/wallets/fake.py index 99010c760..e4f88ae7e 100644 --- a/lnbits/wallets/fake.py +++ b/lnbits/wallets/fake.py @@ -133,6 +133,6 @@ class FakeWallet(Wallet): return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: value: Bolt11 = await self.queue.get() yield value.payment_hash diff --git a/lnbits/wallets/lnbits.py b/lnbits/wallets/lnbits.py index e2674c6ef..aa99b5492 100644 --- a/lnbits/wallets/lnbits.py +++ b/lnbits/wallets/lnbits.py @@ -155,7 +155,7 @@ class LNbitsWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: url = f"{self.endpoint}/api/v1/payments/sse" - while True: + while settings.lnbits_running: try: async with httpx.AsyncClient( timeout=None, headers=self.headers diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 076f151b1..912518058 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -268,7 +268,7 @@ class LndWallet(Wallet): return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: try: request = ln.InvoiceSubscription() async for i in self.rpc.SubscribeInvoices(request): diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index 743abe67e..12ce2a954 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -280,7 +280,7 @@ class LndRestWallet(Wallet): return PaymentPendingStatus() async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: - while True: + while settings.lnbits_running: try: url = "/v1/invoices/subscribe" async with self.client.stream("GET", url, timeout=None) as r: diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index 46aaab003..28842fcba 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -145,6 +145,6 @@ class LNPayWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) - while True: + while settings.lnbits_running: value = await self.queue.get() yield value diff --git a/lnbits/wallets/lntips.py b/lnbits/wallets/lntips.py index a269adb68..b8046bdde 100644 --- a/lnbits/wallets/lntips.py +++ b/lnbits/wallets/lntips.py @@ -152,7 +152,7 @@ class LnTipsWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: last_connected = None - while True: + while settings.lnbits_running: url = "/api/v1/invoicestream" try: last_connected = time.time() diff --git a/lnbits/wallets/opennode.py b/lnbits/wallets/opennode.py index fbab27e01..4e8f3a853 100644 --- a/lnbits/wallets/opennode.py +++ b/lnbits/wallets/opennode.py @@ -141,6 +141,6 @@ class OpenNodeWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) - while True: + while settings.lnbits_running: value = await self.queue.get() yield value diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index 4557699f4..89d0c432b 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -244,7 +244,7 @@ class SparkWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: url = f"/stream?access-key={self.token}" - while True: + while settings.lnbits_running: try: async with self.client.stream("GET", url, timeout=None) as r: async for line in r.aiter_lines(): diff --git a/lnbits/wallets/zbd.py b/lnbits/wallets/zbd.py index 7f939cdd3..d623b20a1 100644 --- a/lnbits/wallets/zbd.py +++ b/lnbits/wallets/zbd.py @@ -154,6 +154,6 @@ class ZBDWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: self.queue: asyncio.Queue = asyncio.Queue(0) - while True: + while settings.lnbits_running: value = await self.queue.get() yield value