Repository navigation
fix(watchdog): restart a wallet whose API stops answering - #3443
Open
Crypto2099 wants to merge 3 commits into
Open
Crypto2099 wants to merge 3 commits into
Crypto2099 wants to merge 3 commits into
Conversation
The watchdog learned about a running wallet only from its exit, so a wallet whose server had ended while its process stayed alive left every request failing until the user restarted it. A ready wallet is now asked for GET /v2/network/information on a new connection every 15 seconds, and after 4 consecutive failures the watchdog stops it and starts a new one on the same port. The check is configured by an optional wallet.health section (absent means off), and the Nix generator emits it for every network. Any HTTP status counts as an answer, because a 404 or a 500 still shows that the server serves requests. A wallet started with tls_dir is probed over mutual TLS with the generated client certificate, using rustls on the ring provider that rcgen already builds, and the generated CA is the only trusted root. A certificate failure in either direction is a configuration fault, so it turns the check off for that wallet process instead of restarting it. Each probe opens a new connection, because a kept-alive connection can keep answering after the loop that accepts new connections is gone. The first request after a wallet starts waits for the wallet's first connection to the node, so before the first answer timeouts are ignored and refused connections count; a wallet that has not answered after 5 minutes is acted on as well. After the machine sleeps or the process is starved, the failure count starts again. A restart for no response stops the wallet, emits wallet_unresponsive and does not emit wallet_restarting, whose attempt counts crashes. These restarts have a separate limit: at most 5 restarts in any hour, counted on a sliding window, and each restart in the window doubles the failure threshold for the next wallet. At the limit the wallet is left stopped and wallet_unrecoverable is emitted, which shows the existing retry. A restart or retry requested by the user clears the count. stop_wallet now returns how the process ended and writes its exit code to the log, so a crash on a requested stop is recorded. The default bound rises from 10 to 60 seconds for requested stops (quit, restarts the user asks for, Mithril and update install), because a wallet that closes its databases while queries are running can take longer than 10 seconds and a kill during that costs time on the next start. A restart for no response and the stop that follows a node exit, which precedes an automatic restart, use the 15-second bound. The wait of a second launch for a stopping instance follows, and is 150 seconds by default. Electron records wallet_unresponsive and Diagnostics shows the number of restarts and the time and last error of the latest one, in the table and in the copied summary. The new strings are in en-US, and in ja-JP as untranslated entries. The probe client, monitor and restart budget are in a health module that does not depend on the wallet. rustls 0.23.46, tokio-rustls 0.26.6, rustls-webpki 0.103.16 and subtle 2.6.1 are added with default features off.
Windows reports a connection attempt to a closed local port only after its SYN retransmissions, about two seconds, where Linux reports it at once. The test used the 400 ms timeout of the other probe tests, so on Windows the timeout fired first, and the probe returned Timeout. It now uses the 10-second timeout the watchdog runs the probe with by default.
Crypto2099
force-pushed
the
fix/wallet-health-check
branch
from
November 3, 2026 22:42
a96f19c to
decff87
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Restarts cardano-wallet when its API stops answering while its process stays alive. Until now the watchdog learned about a running wallet only from its exit, so a wallet whose server had ended left every request failing until the user restarted it from Diagnostics.
Behavior:
GET /v2/network/informationto a ready wallet on a new connection, with a 10 s timeout. Any HTTP status counts as an answer.wallet_ready.tls_diris probed over mutual TLS with the generated client certificate. A certificate failure turns the check off for that wallet process and never restarts it.wallet_unrecoverableis emitted and the existing retry is offered. A restart or retry requested by the user clears the count.wallet_unresponsiveevent carries the failed probe count, time without an answer, whether the wallet ever answered, the last error, the restart number and whether a restart follows. It does not usewallet_restarting, whoseattemptcounts crashes.wallet.healthsection; absent means off. The Nix generator emits the section with defaults for every network.Stop path:
stop_walletreturns how the process ended andwatchdog.logrecords its exit code on every stop.Electron:
wallet_unresponsiveis recorded inWatchdogManager,BackendStoremirrors it, and Diagnostics shows "Wallet restarts after no response" and "Last wallet no-response" in the table and in the copied summary. The rows appear only after a wallet has stopped answering. The state snapshot written to the support logs gainswalletUnresponsiveRestartsandlastWalletUnresponsive.Dependencies:
rustls0.23.46,tokio-rustls0.26.6,rustls-webpki0.103.16 andsubtle2.6.1, with default features off soaws-lc-rsis not built.ring0.17.14 andrustls-pki-types1.15.1 were already in the lockfile throughrcgen.Cargo.lockgains 4 packages (141 to 145).The probe client, monitor and restart budget live in
watchdog/src/health/and know nothing about the wallet.Screenshots
None. The two Diagnostics rows are plain text rows in the existing table and appear only after a wallet has stopped answering.
Verification
Run with
nix build .#checks.x86_64-linux.<name>:watchdog-clippy,watchdog-test,treefmt,compile,lint,jest,i18n,stylelint,cucumber-unitandstorybookall pass.Tests
The monitor and budget are unit-tested with synthetic time. The probe is tested against in-process servers: plain HTTP answering 200, 404 and 500, a listener that never writes, a closed port, and a
tokio-rustlsserver that requires a client certificate, with the generated certificates answering and a certificate from another CA rejected in both directions.mock-walletgains modes that close its listener, mute it, ignore stdin and run healthy on the second process.watchdog/tests/integration.rscovers restart after a closed listener, a kill of a hung server, the stop after a node exit using the short bound, the restart limit and its clearing by a retry, a healthy wallet, the startup grace, refusals before the first answer, clearing by a user restart and the check being off without its section.watchdog/tests/ipc.rsruns the closed-listener case without a platform gate. Jest covers theWatchdogManagerandBackendStorestate.Code quality
@ts-ignoreyarn.lockis updated if dependencies changedReview