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 成功,无越限、重复提交、重复计费、重复回调或终态资源泄漏。
This commit is contained in:
2026-08-03 00:13:46 +08:00
parent 9a01fd4657
commit c28bf74230
52 changed files with 3700 additions and 272 deletions
@@ -155,6 +155,44 @@ func TestForcedConversionRejectsImagesOutsideOfficialSeedanceRange(t *testing.T)
}
}
func TestGeminiProtocolAcceptsMultipleFileDataImages(t *testing.T) {
server := New(Config{Wait: func(context.Context, time.Duration) error { return nil }})
httpServer := httptest.NewServer(server.Handler())
defer httpServer.Close()
parts := []any{map[string]any{"text": "combine references"}}
for index := 0; index < 3; index++ {
parts = append(parts, map[string]any{"fileData": map[string]any{
"mimeType": "image/png",
"fileUri": fmt.Sprintf("https://fixtures.example/%d.png", index),
}})
}
body, _ := json.Marshal(map[string]any{
"contents": []any{map[string]any{"parts": parts}},
"generationConfig": map[string]any{"responseModalities": []any{"IMAGE"}},
})
response, err := postIdempotent(httpServer.URL+"/v1beta/models/gemini-test:generateContent", body, "gemini-multi")
if err != nil {
t.Fatalf("Gemini multi-image request: %v", err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
payload, _ := io.ReadAll(response.Body)
t.Fatalf("Gemini multi-image status=%d body=%s", response.StatusCode, payload)
}
reportResponse, err := http.Get(httpServer.URL + "/report")
if err != nil {
t.Fatalf("get report: %v", err)
}
defer reportResponse.Body.Close()
var report Report
if err := json.NewDecoder(reportResponse.Body).Decode(&report); err != nil {
t.Fatalf("decode report: %v", err)
}
if report.GeminiRequests != 1 || report.GeminiInputImages != 3 || report.GeminiInvalid != 0 {
t.Fatalf("unexpected multi-image report: %+v", report)
}
}
func TestImageFixturesFullyDecode(t *testing.T) {
for name, fixture := range buildFixtures() {
if !strings.HasPrefix(fixture.ContentType, "image/") {