Files
easyai-ai-gateway/apps/api/internal/workerload/controller_test.go
T
wangbo c28bf74230 feat(worker): 实现集群限流与自适应负载
保留平台模型 RPM、TPM 和并发策略语义,增加 PostgreSQL 集群级租约、饱和候选重选和多平台自动负载,避免突发任务固定等待首个平台。\n\n新增 Worker 实时负载采样、自适应 active/heavy 容量、心跳与管理端指标,并扩展本地 acceptance runner,覆盖三 Worker、同模型三平台 2/4/6 并发和 48 个带图视频突发任务。\n\n验证:go test ./...、go vet ./...、PostgreSQL 跨 Store 集成测试、gofmt、bash -n、ShellCheck 及本地集群 provider-burst 验收通过;48/48 成功,无越限、重复提交、重复计费、重复回调或终态资源泄漏。
2026-08-03 00:13:46 +08:00

96 lines
3.1 KiB
Go

package workerload
import (
"context"
"testing"
"time"
)
func TestControllerStartsConservativelyAndGrowsUnderSustainedDemand(t *testing.T) {
controller := New(Config{Mode: ModeAdaptive, HardLimit: 16, InitialActive: 4, InitialHeavy: 1, HealthySamples: 2})
leases := make([]*Lease, 0, 4)
for range 4 {
lease, ok := controller.TryStart()
if !ok {
t.Fatal("initial task was not admitted")
}
_ = lease.EnterWaiting()
leases = append(leases, lease)
}
for range 2 {
controller.Observe(ResourceSample{MemoryCurrentBytes: 40, MemoryLimitBytes: 100, CPUUtilization: .4, DBConnections: 4, DBMaxConnections: 20})
}
snapshot := controller.Snapshot()
if snapshot.ActiveLimit != 5 || snapshot.HeavyLimit != 2 {
t.Fatalf("grown snapshot=%+v, want active=5 heavy=2", snapshot)
}
for _, lease := range leases {
lease.Release()
}
}
func TestControllerBusyAndCriticalPressureReduceNewClaims(t *testing.T) {
controller := New(Config{Mode: ModeAdaptive, HardLimit: 16, InitialActive: 8, InitialHeavy: 2})
busy := controller.Observe(ResourceSample{MemoryCurrentBytes: 80, MemoryLimitBytes: 100})
if busy.PressureState != PressureBusy || busy.SafeCapacity >= 8 {
t.Fatalf("busy snapshot=%+v", busy)
}
critical := controller.Observe(ResourceSample{MemoryCurrentBytes: 95, MemoryLimitBytes: 100})
if critical.PressureState != PressureCritical || critical.SafeCapacity != 0 {
t.Fatalf("critical snapshot=%+v", critical)
}
controller.SetClaimLimit(0)
if _, ok := controller.TryStart(); ok {
t.Fatal("critical controller admitted a new task")
}
}
func TestWaitingReleasesHeavyPermitAndFinalizingReacquiresIt(t *testing.T) {
controller := New(Config{Mode: ModeAdaptive, HardLimit: 4, InitialActive: 4, InitialHeavy: 1})
first, ok := controller.TryStart()
if !ok {
t.Fatal("first lease unavailable")
}
if _, ok := controller.TryStart(); ok {
t.Fatal("second preparing task bypassed heavy limit")
}
if err := first.EnterWaiting(); err != nil {
t.Fatal(err)
}
second, ok := controller.TryStart()
if !ok {
t.Fatal("waiting task did not release heavy permit")
}
if err := second.EnterWaiting(); err != nil {
t.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := first.EnterFinalizing(ctx); err != nil {
t.Fatal(err)
}
blocked := make(chan error, 1)
go func() { blocked <- second.EnterFinalizing(ctx) }()
select {
case err := <-blocked:
t.Fatalf("second finalizer did not wait: %v", err)
case <-time.After(20 * time.Millisecond):
}
first.Release()
if err := <-blocked; err != nil {
t.Fatal(err)
}
second.Release()
if snapshot := controller.Snapshot(); snapshot.ActiveTasks != 0 {
t.Fatalf("active tasks=%d, want 0", snapshot.ActiveTasks)
}
}
func TestLegacyModeUsesHardLimit(t *testing.T) {
controller := New(Config{Mode: ModeLegacy, HardLimit: 7})
snapshot := controller.Observe(ResourceSample{MemoryCurrentBytes: 99, MemoryLimitBytes: 100, CPUUtilization: 1, CPUThrottled: true})
if snapshot.ActiveLimit != 7 || snapshot.HeavyLimit != 7 || snapshot.SafeCapacity != 7 || snapshot.PressureReason != "legacy" {
t.Fatalf("legacy snapshot=%+v", snapshot)
}
}