perf(worker): 持续批量填满异步执行槽

异步准入通知在突发提交时会合并,原调度器每次只填充一个 8 任务批次,导致全局容量长期空闲并反向拖慢入口登记。\n\n收到通知或周期唤醒后连续拉取并提交批次,直到队列为空或全局执行容量真正饱和;保留每批 8 个的短事务边界。\n\n验证:env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1;go vet ./...;gofmt -l 无输出。
This commit is contained in:
2026-07-31 08:32:39 +08:00
parent d5b5d4b4cd
commit 17433bf2da
+15 -2
View File
@@ -704,6 +704,7 @@ func (s *Service) dispatchWaitingAsyncAdmissions(ctx context.Context) {
case <-s.asyncAdmissionWake: case <-s.asyncAdmissionWake:
case <-ticker.C: case <-ticker.C:
} }
for {
batchLimit := s.cfg.AsyncWorkerHardLimit batchLimit := s.cfg.AsyncWorkerHardLimit
if batchLimit <= 0 { if batchLimit <= 0 {
batchLimit = 64 batchLimit = 64
@@ -714,7 +715,10 @@ func (s *Service) dispatchWaitingAsyncAdmissions(ctx context.Context) {
taskIDs, err := s.store.ListWaitingAsyncAdmissionTaskIDs(ctx, batchLimit) taskIDs, err := s.store.ListWaitingAsyncAdmissionTaskIDs(ctx, batchLimit)
if err != nil { if err != nil {
s.logger.Warn("list waiting async admissions failed", "error", err) s.logger.Warn("list waiting async admissions failed", "error", err)
continue break
}
if len(taskIDs) == 0 {
break
} }
tasks := make([]store.GatewayTask, 0, len(taskIDs)) tasks := make([]store.GatewayTask, 0, len(taskIDs))
for _, taskID := range taskIDs { for _, taskID := range taskIDs {
@@ -730,16 +734,25 @@ func (s *Service) dispatchWaitingAsyncAdmissions(ctx context.Context) {
} }
tasks = append(tasks, task) tasks = append(tasks, task)
} }
if len(tasks) == 0 {
break
}
saturated, err := s.dispatchWaitingAsyncTasks(ctx, tasks) saturated, err := s.dispatchWaitingAsyncTasks(ctx, tasks)
if err != nil { if err != nil {
s.logger.Warn("dispatch waiting async admission batch failed", "tasks", len(tasks), "error", err) s.logger.Warn("dispatch waiting async admission batch failed", "tasks", len(tasks), "error", err)
continue break
} }
if saturated { if saturated {
// Every asynchronous task shares the global worker-capacity FIFO // Every asynchronous task shares the global worker-capacity FIFO
// scope. Once its current head cannot be admitted, later tasks // scope. Once its current head cannot be admitted, later tasks
// cannot make progress until a lease is released. // cannot make progress until a lease is released.
s.observeTaskAdmission("dispatch_saturated") s.observeTaskAdmission("dispatch_saturated")
break
}
// PostgreSQL notifications are wake-up hints and collapse while a
// batch is being admitted. Keep filling consecutive batches until
// the global execution scope is actually saturated so a large burst
// cannot strand most Worker slots behind the one-second fallback.
} }
} }
} }