Merge branch 'test-dev'
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -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/
|
||||||
code-reviews/
|
|
||||||
docs/
|
docs/
|
||||||
|
code-reviews/
|
||||||
|
AGENTS.md
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user