From 1659a15f813be176abd7cb68866aef7c6618d8bf Mon Sep 17 00:00:00 2001 From: fontvielle Date: Wed, 21 Oct 2026 14:32:58 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=B0=D1=81=D1=82=D0=B5=D1=80:=20=C2=AB?= =?UTF-8?q?=D0=94=D0=B0=D0=BB=D0=B5=D0=B5=C2=BB=20=D0=BD=D0=B0=20=D1=88?= =?UTF-8?q?=D0=B0=D0=B3=D0=B5=20=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=20=D1=81?= =?UTF-8?q?=D1=80=D0=B0=D0=B7=D1=83=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20?= =?UTF-8?q?=D1=83=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=B8=20+=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B4=D1=91=D0=B6=D0=BD=D0=B0=D1=8F=20=D1=81=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B0=20=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=BE?= =?UTF-8?q?=D1=87=D0=BD=D0=B8=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit После успешной установки ключа на шаге «Ключ и сертификаты» не появлялась кнопка «Далее»: шаг считался выполненным только по асинхронной сверке справочника ИШ (nsdCertsCheck), а она сразу после установки отваливалась по таймауту — root-воркер был занят перезапуском ИШ и повторной активацией профиля. Ключ при этом уже подключён и подписывает. - refreshCertStore: повторяет сверку до 5 раз (воркер освобождается — проходит), вместо одной попытки с таймаутом. - Шаг 8 в мастере выполнен, если справочник собран ИЛИ мастер ключа прошёл до конца (ИШ подтвердил подпись) — «Далее» появляется сразу, не дожидаясь сверки. Добавлен потокобезопасный keyWizardState.installed(). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01Q7eREaYwUt1i4fNLZcGnjn --- deploy/release/component-versions.json | 24 ++++++++++++------------ internal/lkgateway/igate.go | 18 ++++++++++++++---- internal/lkgateway/keywizard.go | 13 +++++++++++++ internal/lkgateway/setup.go | 2 +- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/deploy/release/component-versions.json b/deploy/release/component-versions.json index 175a6d1..f7dfd0b 100644 --- a/deploy/release/component-versions.json +++ b/deploy/release/component-versions.json @@ -1,27 +1,27 @@ { "bj-component-install": { - "fingerprint": "61cfd9db5bd1d70d74f6fde0f6c37d18747c8310197a9942abc7139dc3b86687", - "version": "2026.10.21.4" + "fingerprint": "0a79da1c0f89a4fb5b5d16932c586f489990e3a11764c957f3e653de22084232", + "version": "2026.10.21.5" }, "bj-installer": { - "fingerprint": "8598d4f35fc05d882596e8e4a599f44443cbfa3b0f6ea5c4de4ecbfadd5dab01", - "version": "2026.10.21.4" + "fingerprint": "1bcb6d36b95509de3796bd57dd4da2780621f25111d5d4734e906e0a1e38269d", + "version": "2026.10.21.5" }, "bj-lk": { - "fingerprint": "48a6cac59febba3392c854423b729f426383d86d35514578b5546786c8ab3355", - "version": "2026.10.21.4" + "fingerprint": "37bf4ba7d13bc3cfb52032dfb95851b9d5d702f1a2244e185a1b6a5b87a5cfc6", + "version": "2026.10.21.5" }, "bj-npr": { - "fingerprint": "357f7562645da12ec4689927f5599a2aa22996a34bd82b36f80ece26629ac036", - "version": "2026.10.21.4" + "fingerprint": "5b5301b0c18bfd001bdff3f3b35a9ff6ccccb4f24eb4b88b0334d34d1b63df81", + "version": "2026.10.21.5" }, "bj-quikexport": { - "fingerprint": "136cb4068888239e792d4eaedb973f430ce01542d124066fc914847a147c3549", - "version": "2026.10.21.4" + "fingerprint": "f7761571352f17173c10989f72a3a9686e58cfc0c0a78ae7299bacbe31d36df6", + "version": "2026.10.21.5" }, "bj-server": { - "fingerprint": "b4ea83379567a8d6be59005c79d11c5dbe972a5108b832b9344467f970f26b71", - "version": "2026.10.21.4" + "fingerprint": "82e5b9edb95339be67b1d9d46fc3cb6a5ff2b8540606d83f12c8c5d95be8af3f", + "version": "2026.10.21.5" }, "crypto-service.jar": { "fingerprint": "2c4fd536bc9b1c20c69a70e8dcd374a61847b263aeb2e474c45debb01fbd8233", diff --git a/internal/lkgateway/igate.go b/internal/lkgateway/igate.go index 20bcba1..1637934 100644 --- a/internal/lkgateway/igate.go +++ b/internal/lkgateway/igate.go @@ -365,10 +365,20 @@ func registerIgateAdmin(mux *http.ServeMux, rc *RuntimeConfig) { func refreshCertStore(rc *RuntimeConfig) { go func() { time.Sleep(20 * time.Second) // ИШ перезапускается после изменений - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancel() - if _, err := nsdCertsCheck(ctx, rc); err != nil { - log.Printf("nsdcerts: перечитать справочник: %v", err) + // root-воркер обрабатывает запросы по одному и сразу после установки ключа + // (перезапуск ИШ, повторная активация профиля) бывает занят — одной попытки + // может не хватить, она отваливается по таймауту. Повторяем, пока сверка не + // пройдёт: без свежего справочника шаг «Ключ и сертификаты» остаётся + // невыполненным и в мастере нет кнопки «Далее», хотя ключ уже подписывает. + for attempt := 1; attempt <= 5; attempt++ { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + _, err := nsdCertsCheck(ctx, rc) + cancel() + if err == nil { + return + } + log.Printf("nsdcerts: перечитать справочник (попытка %d/5): %v", attempt, err) + time.Sleep(30 * time.Second) } }() } diff --git a/internal/lkgateway/keywizard.go b/internal/lkgateway/keywizard.go index c6cb5b9..ad8672c 100644 --- a/internal/lkgateway/keywizard.go +++ b/internal/lkgateway/keywizard.go @@ -55,6 +55,19 @@ func newKeyWizardState() *keyWizardState { return &keyWizardState{Steps: defaultKeySteps()} } +// installed — мастер ключа прошёл до конца (ключ подключён и ИШ подтвердил подпись). +// Это более надёжный признак, чем асинхронная сверка справочника: по нему шаг +// «Ключ и сертификаты» считается выполненным сразу, не дожидаясь перечитывания +// справочника. nil-приёмник допустим (мастер ещё не запускался). +func (s *keyWizardState) installed() bool { + if s == nil { + return false + } + s.mu.Lock() + defer s.mu.Unlock() + return s.Done +} + // reset обнуляет поля прогона, НЕ трогая мьютекс (вызывать под Lock). func (s *keyWizardState) reset() { s.StagingID = "" diff --git a/internal/lkgateway/setup.go b/internal/lkgateway/setup.go index 276aed8..0253cb9 100644 --- a/internal/lkgateway/setup.go +++ b/internal/lkgateway/setup.go @@ -290,7 +290,7 @@ func (h *setupHandlers) renderWizard(w http.ResponseWriter, r *http.Request) { d.Done.Users = doneUsers() _, wizUpdAvail := updateComponentRows(h.rc) // шаг 14 «Обновление»: зелёный, пока нет версии новее done := map[int]bool{1: d.Done.License, 2: d.Done.Postgres, 3: d.Done.Depo, 4: d.Done.Org, 5: d.Done.Quik, 6: d.Done.Crypto, - 7: d.Done.NSD, 8: d.Done.Certs, 9: d.Done.Alerts, 10: d.Done.TestRun, 11: d.Done.Modules, 12: d.Done.Server, 13: d.Done.Users, 14: !wizUpdAvail} + 7: d.Done.NSD, 8: d.Done.Certs || h.keyWiz.installed(), 9: d.Done.Alerts, 10: d.Done.TestRun, 11: d.Done.Modules, 12: d.Done.Server, 13: d.Done.Users, 14: !wizUpdAvail} path, _ := wizPath(h.rc, done, 0) step := wizDefaultStep(path, done) if v := r.URL.Query().Get("step"); v != "" {