Merge branch 'test-dev'

This commit is contained in:
yangjianbo
2025-12-30 14:36:52 +08:00
2 changed files with 28 additions and 39 deletions

4
.gitignore vendored
View File

@@ -108,9 +108,11 @@ backend/.installed
# =================== # ===================
tests tests
CLAUDE.md CLAUDE.md
AGENTS.md
.claude .claude
scripts scripts
.code-review-state .code-review-state
openspec/ openspec/
docs/
code-reviews/ code-reviews/
docs/ AGENTS.md

View File

@@ -457,10 +457,11 @@ func (r *accountRepository) ListSchedulableByPlatform(ctx context.Context, platf
} }
func (r *accountRepository) ListSchedulableByGroupIDAndPlatform(ctx context.Context, groupID int64, platform string) ([]service.Account, error) { func (r *accountRepository) ListSchedulableByGroupIDAndPlatform(ctx context.Context, groupID int64, platform string) ([]service.Account, error) {
// 单平台查询复用多平台逻辑,保持过滤条件与排序策略一致。
return r.queryAccountsByGroup(ctx, groupID, accountGroupQueryOptions{ return r.queryAccountsByGroup(ctx, groupID, accountGroupQueryOptions{
status: service.StatusActive, status: service.StatusActive,
schedulable: true, schedulable: true,
platform: platform, platforms: []string{platform},
}) })
} }
@@ -468,50 +469,35 @@ func (r *accountRepository) ListSchedulableByPlatforms(ctx context.Context, plat
if len(platforms) == 0 { if len(platforms) == 0 {
return nil, nil return nil, nil
} }
var accounts []accountModel // 仅返回可调度的活跃账号,并过滤处于过载/限流窗口的账号。
// 代理与分组信息统一在 accountsToService 中批量加载,避免 N+1 查询。
now := time.Now() now := time.Now()
err := r.db.WithContext(ctx). accounts, err := r.client.Account.Query().
Where("platform IN ?", platforms). Where(
Where("status = ? AND schedulable = ?", service.StatusActive, true). dbaccount.PlatformIn(platforms...),
Where("(overload_until IS NULL OR overload_until <= ?)", now). dbaccount.StatusEQ(service.StatusActive),
Where("(rate_limit_reset_at IS NULL OR rate_limit_reset_at <= ?)", now). dbaccount.SchedulableEQ(true),
Preload("Proxy"). dbaccount.Or(dbaccount.OverloadUntilIsNil(), dbaccount.OverloadUntilLTE(now)),
Order("priority ASC"). dbaccount.Or(dbaccount.RateLimitResetAtIsNil(), dbaccount.RateLimitResetAtLTE(now)),
Find(&accounts).Error ).
Order(dbent.Asc(dbaccount.FieldPriority)).
All(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
outAccounts := make([]service.Account, 0, len(accounts)) return r.accountsToService(ctx, accounts)
for i := range accounts {
outAccounts = append(outAccounts, *accountModelToService(&accounts[i]))
}
return outAccounts, nil
} }
func (r *accountRepository) ListSchedulableByGroupIDAndPlatforms(ctx context.Context, groupID int64, platforms []string) ([]service.Account, error) { func (r *accountRepository) ListSchedulableByGroupIDAndPlatforms(ctx context.Context, groupID int64, platforms []string) ([]service.Account, error) {
if len(platforms) == 0 { if len(platforms) == 0 {
return nil, nil return nil, nil
} }
var accounts []accountModel // 复用按分组查询逻辑,保证分组优先级 + 账号优先级的排序与筛选一致。
now := time.Now() return r.queryAccountsByGroup(ctx, groupID, accountGroupQueryOptions{
err := r.db.WithContext(ctx). status: service.StatusActive,
Joins("JOIN account_groups ON account_groups.account_id = accounts.id"). schedulable: true,
Where("account_groups.group_id = ?", groupID). platforms: platforms,
Where("accounts.platform IN ?", platforms). })
Where("accounts.status = ? AND accounts.schedulable = ?", service.StatusActive, true).
Where("(accounts.overload_until IS NULL OR accounts.overload_until <= ?)", now).
Where("(accounts.rate_limit_reset_at IS NULL OR accounts.rate_limit_reset_at <= ?)", now).
Preload("Proxy").
Order("account_groups.priority ASC, accounts.priority ASC").
Find(&accounts).Error
if err != nil {
return nil, err
}
outAccounts := make([]service.Account, 0, len(accounts))
for i := range accounts {
outAccounts = append(outAccounts, *accountModelToService(&accounts[i]))
}
return outAccounts, nil
} }
func (r *accountRepository) SetRateLimited(ctx context.Context, id int64, resetAt time.Time) error { func (r *accountRepository) SetRateLimited(ctx context.Context, id int64, resetAt time.Time) error {
@@ -666,20 +652,21 @@ func (r *accountRepository) BulkUpdate(ctx context.Context, ids []int64, updates
type accountGroupQueryOptions struct { type accountGroupQueryOptions struct {
status string status string
schedulable bool schedulable bool
platform string platforms []string // 允许的多个平台,空切片表示不进行平台过滤
} }
func (r *accountRepository) queryAccountsByGroup(ctx context.Context, groupID int64, opts accountGroupQueryOptions) ([]service.Account, error) { func (r *accountRepository) queryAccountsByGroup(ctx context.Context, groupID int64, opts accountGroupQueryOptions) ([]service.Account, error) {
q := r.client.AccountGroup.Query(). q := r.client.AccountGroup.Query().
Where(dbaccountgroup.GroupIDEQ(groupID)) Where(dbaccountgroup.GroupIDEQ(groupID))
// 通过 account_groups 中间表查询账号,并按需叠加状态/平台/调度能力过滤。
preds := make([]dbpredicate.Account, 0, 6) preds := make([]dbpredicate.Account, 0, 6)
preds = append(preds, dbaccount.DeletedAtIsNil()) preds = append(preds, dbaccount.DeletedAtIsNil())
if opts.status != "" { if opts.status != "" {
preds = append(preds, dbaccount.StatusEQ(opts.status)) preds = append(preds, dbaccount.StatusEQ(opts.status))
} }
if opts.platform != "" { if len(opts.platforms) > 0 {
preds = append(preds, dbaccount.PlatformEQ(opts.platform)) preds = append(preds, dbaccount.PlatformIn(opts.platforms...))
} }
if opts.schedulable { if opts.schedulable {
now := time.Now() now := time.Now()