fix(console): release busy gate when the fast worker stops
When the daemon disconnects, teardown stops the fast RPC worker without draining its queued main-thread callbacks. The console busy gate was released inside that callback, so a command whose callback was discarded left the input disabled for the rest of the session. - The busy gate now drops from an RAII guard at the end of the worker job itself, so it is released however the job ends: success, error, or a worker torn down undrained. - The result is published to the console before the gate drops, so a freed-up console always has the output queued. - An unknown, non-std::exception failure is now caught and reported instead of escaping the job. User-visible: the Console input can no longer stay stuck disabled after a reconnect. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -943,7 +943,7 @@ void App::onDisconnected(const std::string& reason)
|
||||
// curl_easy_perform unblocks and stop()'s join() returns promptly (no UI freeze).
|
||||
if (fast_rpc_) fast_rpc_->requestAbort();
|
||||
if (fast_worker_) {
|
||||
fast_worker_->stop();
|
||||
fast_worker_->stop(); // undrained MainCbs are lost; console busy gate is released worker-side
|
||||
// Drop the stopped worker so onConnected recreates and starts a fresh one. Keeping a
|
||||
// stopped-but-present worker would defeat onConnected's `if (!fast_worker_)` guard, leaving
|
||||
// the fast lane dead for the rest of the session — which silently stalls the opid poll
|
||||
|
||||
@@ -121,6 +121,12 @@ void FullNodeConsoleExecutor::submit(const std::string& cmd)
|
||||
if (worker) {
|
||||
in_flight_.fetch_add(1); // gates busy() so the input is disabled until this returns
|
||||
worker->post([rpc, method, params, this]() -> rpc::RPCWorker::MainCb {
|
||||
// Drops the busy gate when the worker job ends, however it ends. The gate used to drop in the
|
||||
// MainCb, which is lost when teardown stops the fast worker undrained, leaving busy() stuck.
|
||||
struct ReleaseGate {
|
||||
std::atomic<int>& n;
|
||||
~ReleaseGate() { n.fetch_sub(1); }
|
||||
} gate{in_flight_};
|
||||
std::string result_str;
|
||||
bool is_error = false;
|
||||
try {
|
||||
@@ -129,14 +135,19 @@ void FullNodeConsoleExecutor::submit(const std::string& cmd)
|
||||
} catch (const std::exception& e) {
|
||||
result_str = e.what();
|
||||
is_error = true;
|
||||
} catch (...) {
|
||||
result_str = "RPC failed (unknown error)";
|
||||
is_error = true;
|
||||
}
|
||||
return [this, result_str, is_error]() {
|
||||
in_flight_.fetch_sub(1);
|
||||
{
|
||||
// Publish the result before the gate drops, so a non-busy console always has it queued.
|
||||
std::lock_guard<std::mutex> lk(results_mutex_);
|
||||
results_.push_back({result_str, is_error});
|
||||
}
|
||||
return [this]() {
|
||||
// A Console command may have changed the wallet (a send, an import, a new address): the
|
||||
// scans gated on change signals must look again. (Main thread: this is a drained callback.)
|
||||
if (app_) app_->noteWalletMutation();
|
||||
std::lock_guard<std::mutex> lk(results_mutex_);
|
||||
results_.push_back({result_str, is_error});
|
||||
};
|
||||
});
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user