From d35f74355f60319aaa99d095d4cf5f7082a4f2ec Mon Sep 17 00:00:00 2001 From: smail Date: Sun, 6 Sep 2026 06:38:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BF=81=E7=A7=BB=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E6=8E=92=E7=A9=BA=E5=8F=96=E6=B6=88=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/services/dbmigration/maintenance.go | 10 +++++----- backend/services/dbmigration/maintenance_test.go | 6 +++++- backend/services/dbmigration/service.go | 5 ++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/backend/services/dbmigration/maintenance.go b/backend/services/dbmigration/maintenance.go index 568e312..0aecd34 100644 --- a/backend/services/dbmigration/maintenance.go +++ b/backend/services/dbmigration/maintenance.go @@ -63,20 +63,20 @@ func (lease *requestLease) release() { // 只有权限、请求体与一次性票据均已验证,才排空请求并独占迁移。 // 独占状态由外层中间件持有到会话响应提交完成,不能在控制器返回前释放。 -func (s *Service) drainRequests(ctx context.Context) func() { +func (s *Service) drainRequests(ctx context.Context) (func(), error) { if lease, ok := ctx.Value(requestLeaseKey{}).(*requestLease); ok && lease.service == s { lease.service.requests.RUnlock() if !lease.service.requests.lockContext(ctx) { lease.service = nil - return func() {} + return func() {}, contextError(ctx) } lease.exclusive = true - return func() {} + return func() {}, nil } if !s.requests.lockContext(ctx) { - return func() {} + return func() {}, contextError(ctx) } - return s.requests.Unlock + return s.requests.Unlock, nil } func maintenanceRequest(r *http.Request) bool { diff --git a/backend/services/dbmigration/maintenance_test.go b/backend/services/dbmigration/maintenance_test.go index 553aeee..604171c 100644 --- a/backend/services/dbmigration/maintenance_test.go +++ b/backend/services/dbmigration/maintenance_test.go @@ -50,7 +50,11 @@ func TestMaintenanceGuardDrainsRequestsAndKeepsRestartRoute(t *testing.T) { close(entered) <-release case "/api/v1/database/migrations": - release := service.drainRequests(r.Context()) + release, err := service.drainRequests(r.Context()) + if err != nil { + http.Error(w, err.Error(), http.StatusRequestTimeout) + return + } defer release() executor.paused.Store(true) close(migrated) diff --git a/backend/services/dbmigration/service.go b/backend/services/dbmigration/service.go index 599a131..752f46b 100644 --- a/backend/services/dbmigration/service.go +++ b/backend/services/dbmigration/service.go @@ -223,8 +223,11 @@ func (s *Service) execute(ctx context.Context, id, token string, actor config.Au item.targetConfig = config.DatabaseConfig{} s.mu.Unlock() - releaseRequests := s.drainRequests(ctx) + releaseRequests, drainErr := s.drainRequests(ctx) defer releaseRequests() + if drainErr != nil { + return s.fail(id, drainErr) + } if err := contextError(ctx); err != nil { return s.fail(id, err) }