Route HTTPException (app- and framework-raised), RequestValidationError
and uncaught exceptions through build_error_response so every error body
is {detail, error_code, report?, trace?}. Fixes the bare-string body that
string HTTPException details produced, and registers the handler on the
Starlette base HTTPException so framework 404/405/415 also carry the full
envelope.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_do_electrs_status_advanced only handled the negative cases: each guard
set installed/configured/status to its false-y value and returned early.
On the happy path (electrs installed, configured and running) it fell
through, populated the ports and sync details, but never set
s.installed/s.configured/s.status - so they kept their AppStatus
defaults (False/False/offline).
The /apps/status_advanced/electrs endpoint therefore reported electrs as
not installed and offline while simultaneously returning its ports and
sync details, disagreeing with the app_state_update_message status
(fusion44/blitz_api#286). Set the positive values when each guard passes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BaseChannelListener.listen() only called pubsub.unsubscribe() in its
finally block: the pubsub connection and the listener's own Redis client
were never released, leaking a connection for every install/uninstall
(_watcher) and every recreation of the app-status listener. The Celery
task notifiers were likewise never closed, and used the deprecated
Redis.close() instead of aclose().
- add aclose() to BaseChannelNotifier and BaseChannelListener
- listen() now closes the pubsub and its Redis client in finally
- close the notifiers in the app_manage / app_status_update tasks and
switch to aclose()
- back off in the app-status watch loop so a Redis outage no longer
spins, and drop a leftover debug print
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
get_event_loop() is deprecated on Python 3.11+ when there is no running
loop and is slated to change behaviour further.
- SSEManager.setup() ran at import time (app.api.utils) via
get_event_loop(); this only worked because uvicorn imports the app
inside its loop and would break when imported without a running loop
(e.g. a Celery worker). Start the broadcast consumer lazily from
within a running loop instead.
- everywhere else the pattern was get_event_loop().create_task(x)
inside a coroutine; replace with asyncio.create_task(x).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- uninstall_app dropped input.keep_data; _manage_app always ran the
bonus script with a bare 'off', so the RaspiBlitz script fell back to
an interactive whiptail prompt that hangs the non-interactive API.
Thread keep_data through and pass the explicit
--keep-data/--delete-data flag the scripts expect.
- install.{app_id}.log rendered as install.AppId.MEMPOOL.log because
str-enum formatting includes the class name on Python 3.11+; use
app_id.value here and in the CLN-incompatibility message.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
app_manage_task_impl released APP_MANAGE_LOCK_KEY and broadcast a
FINISHED message from its finally block unconditionally, including on
the early-return path where acquire_lock reported the lock as already
held by a running install. A duplicate install/uninstall request would
therefore delete the running task's lock (allowing concurrent
management of the same app) and send FINISHED, which stopped that
task's AppManageListener before it was done.
Track whether this task actually acquired the lock and only
release + finish when it did.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This is a feature that allows to fetch the app status via a celery
task which stores the result in the Redis database and notifies the API
of the change. The API sends a notification to connected clients via the
SSE mechanism.
Using a background task allows to avoid crashing the whole API if the
script call fails.
The by default the cache is refreshed every 30 minutes. This can be
changed by setting the `BAPI_APP_STATUS_UPDATE_INTERVAL_MIN` environment
variable.
refs #123
If the environment variable BAPI_ENV_PATH is set, the config system will
try to read configs from the given path instead of .env in pwd
If no file is found .env in pwd will be used as a fallback
Env variables will always override settings in .env files.
Some apps might give status information that is computationally to
expensive to include in the normal status endpoint which can be polled
more often.
closes#237
* add joinmarket-webui to available apps
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
* loop thru versions of apps
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>