From 27f25386a88b1574d4be669211205674ae91bd03 Mon Sep 17 00:00:00 2001 From: lime Date: Sat, 23 May 2026 22:24:54 +0800 Subject: [PATCH 1/2] refactor: use exponential backoff for dev server retry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace fixed 500ms sleep with exponential backoff (250ms base, 2× per attempt, capped at 5s). - This extends the total retry window beyond the original 5-second limit, giving slower-starting dev servers enough time to fully boot without being misjudged or prematurely killed. --- v3/pkg/application/application_dev.go | 50 ++++++++++++++++----------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/v3/pkg/application/application_dev.go b/v3/pkg/application/application_dev.go index e12033e33e8..fb3b806aae2 100644 --- a/v3/pkg/application/application_dev.go +++ b/v3/pkg/application/application_dev.go @@ -11,31 +11,39 @@ import ( var devMode = false +// preRun is called before the application starts. In dev mode it waits for the +// frontend dev server to become reachable, retrying up to 10 times with +// exponential backoff (250 ms base, capped at 5 s per attempt). func (a *App) preRun() error { - // Check for frontend server url frontendURL := assetserver.GetDevServerURL() - if frontendURL != "" { - devMode = true - // We want to check if the frontend server is running by trying to http get the url - // and if it is not, we wait 500ms and try again for a maximum of 10 times. If it is - // still not available, we return an error. - // This is to allow the frontend server to start up before the backend server. - client := http.Client{} - a.Logger.Info("Waiting for frontend dev server to start...", "url", frontendURL) - for i := 0; i < 10; i++ { - _, err := client.Get(frontendURL) - if err == nil { - a.Logger.Info("Connected to frontend dev server!") - return nil - } - // Wait 500ms - time.Sleep(500 * time.Millisecond) - if i%2 == 0 { - a.Logger.Info("Retrying...") - } + if frontendURL == "" { + return nil + } + + devMode = true + a.Logger.Info("Waiting for frontend dev server to start...", "url", frontendURL) + + const ( + maxRetries = 10 + maxDelay = 5 * time.Second + ) + client := http.DefaultClient + delay := 250 * time.Millisecond + + for i := range maxRetries { + _, err := client.Get(frontendURL) + if err == nil { + a.Logger.Info("Connected to frontend dev server!") + return nil + } + a.Logger.Info("Retrying...", "attempt", i+1, "next_delay", delay) + time.Sleep(delay) + if delay *= 2; delay > maxDelay { + delay = maxDelay } - a.fatal("unable to connect to frontend server. Please check it is running - FRONTEND_DEVSERVER_URL='%s'", frontendURL) } + + a.fatal("unable to connect to frontend server. Please check it is running - FRONTEND_DEVSERVER_URL='%s'", frontendURL) return nil } From d714c903e371b5ce13d1fd6fbdf60c0d62516d96 Mon Sep 17 00:00:00 2001 From: lime Date: Sat, 23 May 2026 23:10:03 +0800 Subject: [PATCH 2/2] chore: update changelog --- v3/UNRELEASED_CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/v3/UNRELEASED_CHANGELOG.md b/v3/UNRELEASED_CHANGELOG.md index 2ebe4eb0b50..b0359077257 100644 --- a/v3/UNRELEASED_CHANGELOG.md +++ b/v3/UNRELEASED_CHANGELOG.md @@ -20,6 +20,7 @@ After processing, the content will be moved to the main changelog and this file ## Changed +- Use exponential backoff when waiting for the frontend dev server to become reachable, extending the total retry window to ~32 s and preventing premature failures when dev servers are slow to start (#5504) ## Fixed