fix(lite): fast retry when a server is only warming up (-28)

When the preferred lightwalletd server is reachable but warming up (JSON-RPC -28
/ "Activating best chain"), the failover treated it like a dead server and fell
through to the others, so the wallet didn't open until the next 20s retry — even
though the healthy server was ready within seconds.

Detect the warmup error during failover, flag it on the open outcome
(lastOpenWasWarmup()), and have the App retry on a short ~4s interval in that case
instead of 20s, so the wallet opens promptly once warmup clears. A unit test
covers a warming-preferred + dead-fallback open setting the flag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 21:26:14 -05:00
parent dc07491abb
commit 3d4b013b0c
5 changed files with 61 additions and 8 deletions

View File

@@ -173,6 +173,10 @@ public:
void pumpAsyncOpen();
bool openInProgress() const { return openRunning_ && openRunning_->load(); }
const std::string& lastOpenError() const { return lastOpenError_; }
// True if the last failed open hit a server that was merely warming up (JSON-RPC -28 /
// "Activating best chain"): the server is healthy and will be ready shortly, so the caller
// should retry sooner rather than waiting out the normal interval.
bool lastOpenWasWarmup() const { return lastOpenWarming_; }
bool syncStarted() const { return syncStarted_; }
bool syncComplete() const { return syncDone_ && syncDone_->load(); }
@@ -290,13 +294,14 @@ private:
// the detached thread captures only shared_ptrs + value copies, never `this`, so it can
// safely outlive the controller). pumpAsyncOpen() finalizes the result on the main thread.
std::vector<std::string> failoverServerUrls() const;
struct OpenOutcome { bool ok = false; std::string serverUrl; std::string error; };
struct OpenOutcome { bool ok = false; bool warming = false; std::string serverUrl; std::string error; };
std::thread openThread_;
std::shared_ptr<std::atomic<bool>> openRunning_ = std::make_shared<std::atomic<bool>>(false);
std::shared_ptr<std::mutex> openResultMutex_ = std::make_shared<std::mutex>();
std::shared_ptr<std::optional<OpenOutcome>> openResult_ =
std::make_shared<std::optional<OpenOutcome>>();
std::string lastOpenError_; // main-thread only
bool lastOpenWarming_ = false; // last failed open hit a warming-up (-28) server
// Joinable background refresh worker (fast iterations: syncstatus, plus data once synced).
std::thread worker_;