fix(daemon): actually stop an external daemon on quit when the setting is on

"Stop external daemon" silently left an external dragonxd running. beginShutdown()
calls rpc_->requestAbort() (a sticky abort flag, cleared only by connect()) to
unblock in-flight requests; the shutdown thread's stopEmbeddedDaemon() then sent
the graceful "stop" over that same connection, so curl self-aborted it
(CURLE_ABORTED_BY_CALLBACK). doRPC swallowed the error but stop_sent was set true
anyway, skipping the temp-connection fallback that would have worked — so the
daemon never received "stop" and only died via the 20s by-name force-kill (which
collides with the 8s "Force Quit / may corrupt chain data" prompt, so it read as
"doesn't work").

Clear the abort before the shutdown stop and send it synchronously via
sendStopCommandSafely so real delivery success is surfaced (and the fallback can
still run on failure). The graceful stop now reaches the daemon, it exits in a
second or two, and the 20s stall / Force-Quit prompt no longer appears.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 00:08:08 -05:00
parent 5edbe8a276
commit 08aed34bbe

View File

@@ -5047,17 +5047,17 @@ void App::stopEmbeddedDaemon()
// daemon flush state, save block indexes, close sockets, etc.
bool stop_sent = false;
// Try the existing RPC connection first
// Try the existing RPC connection first. beginShutdown() called rpc_->requestAbort() to unblock any
// in-flight request — but that sticky abort (cleared only by connect()) would make THIS "stop" self-
// abort mid-flight (CURLE_ABORTED_BY_CALLBACK). The old async rpc_->stop() swallowed that error yet
// set stop_sent=true, so the daemon never heard "stop" and the working temp-connection fallback was
// skipped — which is why "Stop external daemon" left an external dragonxd running (it only died via
// the 20s force-kill). Clear the abort and send SYNCHRONOUSLY so real success is surfaced.
if (rpc_ && rpc_->isConnected()) {
DEBUG_LOGF("Sending stop command via existing RPC connection...\n");
try {
rpc_->stop([](const json&) {
DEBUG_LOGF("Stop command acknowledged by daemon\n");
});
rpc_->clearAbort();
if (sendStopCommandSafely(*rpc_, "existing connection stop"))
stop_sent = true;
} catch (...) {
DEBUG_LOGF("Failed to send stop via existing connection\n");
}
}
// If the main connection wasn't established (e.g. daemon was still