Skip to content

fix(mint): handle websocket disconnect frames cleanly#1014

Merged
a1denvalu3 merged 1 commit into
cashubtc:mainfrom
b-l-u-e:fix/mint-handle-websocket-disconnect-frames-cleanly
May 28, 2026
Merged

fix(mint): handle websocket disconnect frames cleanly#1014
a1denvalu3 merged 1 commit into
cashubtc:mainfrom
b-l-u-e:fix/mint-handle-websocket-disconnect-frames-cleanly

Conversation

@b-l-u-e

@b-l-u-e b-l-u-e commented May 21, 2026

Copy link
Copy Markdown
Contributor

While reviewing and testing fix(websocket): support generic quote kinds, websocket integration tests passed but produced noisy teardown errors in the mint logs. This PR fixes the underlying disconnect handling

Root cause: LedgerEventClientManager.start() treated a websocket.disconnect frame as “no text, keep looping” instead of exiting. On server shutdown (ASGI 1012), the loop called receive() again, which raised RuntimeError, triggered a double-close, and logged ERROR | Exception in ASGI application.

Motivation

While running websocket subscription tests for the generic quote kinds PR:

poetry run pytest tests/wallet/test_wallet_subscription.py -q

All tests passed (3 passed), but pytest teardown produced alarming mint logs:

Before (broken teardown)

TRACE | 127.0.0.1:45068 - ASGI [14] Receive {'type': 'websocket.disconnect', 'code': 1012}
DEBUG | cashu.mint.router:websocket_endpoint:231 | Exception: Cannot call "receive" once a disconnect message has been received.
TRACE | 127.0.0.1:45068 - ASGI [14] Send {'type': 'websocket.close', 'code': 1000, 'reason': ''}
TRACE | 127.0.0.1:45068 - ASGI [14] Raised exception
ERROR | Exception in ASGI application
INFO  | connection closed

The disconnect frame was received, but the receive loop ignored it and called receive() again.

After (clean teardown)

TRACE | 127.0.0.1:50118 - ASGI [8] Receive {'type': 'websocket.disconnect', 'code': 1012}
DEBUG | cashu.mint.router:websocket_endpoint:227 | Websocket disconnected:
TRACE | 127.0.0.1:50118 - ASGI [8] Completed
INFO  | connection closed

No exception, no double-close, no ASGI error.

Changes

  • cashu/mint/events/client.py — exit the receive loop when a websocket.disconnect frame is received (raise WebSocketDisconnect with the frame's code).
  • cashu/mint/router.py — unify websocket endpoint cleanup:
    • always remove the client from the event manager in finally
    • only call websocket.close() if the socket is not already disconnected
  • tests/mint/test_mint_websocket_protocol.py — add regression test for disconnect frame handling

Signed-off-by: b-l-u-e <8102260+blue@users.noreply.github.com>
@codecov

codecov Bot commented May 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 33.33333% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 74.99%. Comparing base (a1ff72c) to head (5513703).
⚠️ Report is 52 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
cashu/mint/router.py 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1014      +/-   ##
==========================================
+ Coverage   74.90%   74.99%   +0.08%     
==========================================
  Files          99      111      +12     
  Lines       11685    12066     +381     
==========================================
+ Hits         8753     9049     +296     
- Misses       2932     3017      +85     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@a1denvalu3

Copy link
Copy Markdown
Collaborator

Very nice PR thank you!

@a1denvalu3 a1denvalu3 merged commit 620d629 into cashubtc:main May 28, 2026
57 of 58 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in nutshell May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants