diff --git a/internal/lkgateway/readiness.go b/internal/lkgateway/readiness.go index 729dbf0..0ce1c8c 100644 --- a/internal/lkgateway/readiness.go +++ b/internal/lkgateway/readiness.go @@ -453,20 +453,63 @@ func readyDepo(ctx context.Context, rc *RuntimeConfig) ReadyCheck { return c } -// lastReadiness — итог последней проверки готовности: по нему отмечается шаг 10 мастера. +// lastReadiness — итог последней проверки готовности: по нему отмечается шаг 10 мастера. Хранится в +// файле: после перезапуска bj (обновления) шаг не должен снова становиться «не выполнен», а главная — +// показывать «Требуется настройка». Пройденная проверка держится, пока следующая не покажет ошибку. var lastReadiness struct { sync.Mutex - ready bool - at time.Time + ready bool + at time.Time + loaded bool } +const readinessFile = "/var/lib/bj/.bj/readiness.json" + func readinessDone() bool { lastReadiness.Lock() defer lastReadiness.Unlock() - return lastReadiness.ready && time.Since(lastReadiness.at) < 24*time.Hour + if !lastReadiness.loaded { + lastReadiness.loaded = true + var f struct { + Ready bool `json:"ready"` + At time.Time `json:"at"` + } + if b, err := os.ReadFile(readinessFile); err == nil && json.Unmarshal(b, &f) == nil && lastReadiness.at.IsZero() { + lastReadiness.ready, lastReadiness.at = f.Ready, f.At + } + } + return lastReadiness.ready +} + +// readinessSave — запомнить итог проверки готовности (память и файл). +func readinessSave(ready bool, at time.Time) { + lastReadiness.Lock() + lastReadiness.ready, lastReadiness.at, lastReadiness.loaded = ready, at, true + lastReadiness.Unlock() + if b, err := json.Marshal(map[string]any{"ready": ready, "at": at}); err == nil { + tmp := readinessFile + ".tmp" + if os.WriteFile(tmp, b, 0o640) == nil { + _ = os.Rename(tmp, readinessFile) + } + } } func registerReadiness(mux *http.ServeMux, rc *RuntimeConfig) { + go func() { // итога ещё нет (первый запуск с файлом) — проверить в фоне, не дожидаясь мастера + time.Sleep(time.Minute) + if _, err := os.Stat(readinessFile); err == nil { + return + } + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + ready := true + for _, c := range readinessChecks(ctx, rc) { + if c.Required && c.State != "ok" && c.State != "warn" { + ready = false + } + } + readinessSave(ready, time.Now()) + }() mux.HandleFunc("/admin/setup/readiness", func(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second) defer cancel() @@ -477,9 +520,7 @@ func registerReadiness(mux *http.ServeMux, rc *RuntimeConfig) { ready = false } } - lastReadiness.Lock() - lastReadiness.ready, lastReadiness.at = ready, time.Now() - lastReadiness.Unlock() + readinessSave(ready, time.Now()) jsonOut(w, map[string]any{"checks": checks, "ready": ready, "at": time.Now().Format("02.01.2006 15:04:05")}) }) }