From d2c2b46c9e28dae24c60771bf8c107e17a8122e1 Mon Sep 17 00:00:00 2001 From: Brisbanehuang Date: Sat, 12 Sep 2026 09:06:33 -0400 Subject: [PATCH] =?UTF-8?q?fix(batch-image):=20=E4=BF=AE=E6=AD=A3=E6=89=B9?= =?UTF-8?q?=E9=87=8F=E7=94=9F=E5=9B=BE=E8=B4=A6=E5=8F=B7=E4=BC=98=E5=85=88?= =?UTF-8?q?=E7=BA=A7=E6=8E=92=E5=BA=8F=E6=96=B9=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按较小 priority 优先选择账号,保留同优先级 ID 排序及现有资格过滤。补充选择回归,并将定价夹具对齐实际选中的账号,不改变计费公式。 --- .../internal/service/batch_image_public.go | 3 +- .../service/batch_image_public_test.go | 33 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/backend/internal/service/batch_image_public.go b/backend/internal/service/batch_image_public.go index 580d1f4934..c417ada1b4 100644 --- a/backend/internal/service/batch_image_public.go +++ b/backend/internal/service/batch_image_public.go @@ -944,9 +944,10 @@ func (s *BatchImagePublicService) selectProviderAndAccount(ctx context.Context, if err != nil { return nil, nil, err } + // 与普通账号调度一致:priority 数值越小越优先,同优先级按 ID 排序。 sort.SliceStable(accounts, func(i, j int) bool { if accounts[i].Priority != accounts[j].Priority { - return accounts[i].Priority > accounts[j].Priority + return accounts[i].Priority < accounts[j].Priority } return accounts[i].ID < accounts[j].ID }) diff --git a/backend/internal/service/batch_image_public_test.go b/backend/internal/service/batch_image_public_test.go index a69468f846..67ec00e13a 100644 --- a/backend/internal/service/batch_image_public_test.go +++ b/backend/internal/service/batch_image_public_test.go @@ -16,6 +16,35 @@ import ( "github.com/stretchr/testify/require" ) +func TestBatchImagePublicService_SelectAccountPriority(t *testing.T) { + for _, tt := range []struct { + name string + priorities [2]int + firstBlocked bool + wantID int64 + }{ + {name: "lower priority value wins even with higher ID", priorities: [2]int{1, 9}, wantID: 202}, + {name: "lower priority value wins regardless of repository order", priorities: [2]int{9, 1}, wantID: 101}, + {name: "equal priorities keep lower ID first", priorities: [2]int{5, 5}, wantID: 101}, + {name: "preferred but unschedulable account is skipped", priorities: [2]int{1, 9}, firstBlocked: true, wantID: 101}, + } { + t.Run(tt.name, func(t *testing.T) { + svc, _, _, _, _ := newTestBatchImagePublicService(true) + accounts := []Account{testBatchImageAccount(202, AccountTypeAPIKey), testBatchImageAccount(101, AccountTypeAPIKey)} + accounts[0].Priority = tt.priorities[0] + accounts[1].Priority = tt.priorities[1] + accounts[0].Schedulable = !tt.firstBlocked + svc.AccountRepo = &publicBatchImageAccountRepo{accounts: accounts} + + provider, account, err := svc.selectProviderAndAccount(context.Background(), testBatchImageOwner(), BatchImageProviderGeminiAPI, "gemini-2.5-flash-image") + require.NoError(t, err) + require.NotNil(t, provider) + require.NotNil(t, account) + require.Equal(t, tt.wantID, account.ID) + }) + } +} + func TestBatchImagePublicService_Submit(t *testing.T) { ctx := context.Background() @@ -54,7 +83,7 @@ func TestBatchImagePublicService_Submit(t *testing.T) { require.Equal(t, "files/gemini_api/input", batchImageDerefString(job.ProviderInputRef)) require.Equal(t, "files/gemini_api/output", batchImageDerefString(job.ProviderOutputRef)) require.NotNil(t, job.AccountID) - require.Equal(t, int64(202), *job.AccountID) + require.Equal(t, int64(101), *job.AccountID) require.Equal(t, 1, job.PricingSnapshotVersion) require.InDelta(t, 0.25, job.BaseUnitPrice, 1e-12) require.InDelta(t, 1.0, job.GroupRateMultiplier, 1e-12) @@ -71,7 +100,7 @@ func TestBatchImagePublicService_Submit(t *testing.T) { groupID := int64(7) accountMultiplier := 1.25 accountRepo := svc.AccountRepo.(*publicBatchImageAccountRepo) - accountRepo.accounts[1].RateMultiplier = &accountMultiplier + accountRepo.accounts[0].RateMultiplier = &accountMultiplier svc.GroupRepo = &publicBatchImageGroupRepo{groups: map[int64]*Group{ groupID: { ID: groupID,