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) }