mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-03 06:52:13 +08:00
feat: add independent load_factor field for scheduling load calculation
- Separate load factor from concurrency: concurrency controls actual slot acquisition, load_factor controls load rate calculation - Add EffectiveLoadFactor() method: LoadFactor > Concurrency > 1 - Add load_factor field to Create/Edit/BulkEdit account forms - Fix RPM default value: auto-fill 15 when RPM enabled but not set - Fix stale test compilation errors in server and handler packages
This commit is contained in:
@@ -1 +1 @@
|
||||
0.1.90.8
|
||||
0.1.90.9
|
||||
|
||||
@@ -41,6 +41,8 @@ type Account struct {
|
||||
ProxyID *int64 `json:"proxy_id,omitempty"`
|
||||
// Concurrency holds the value of the "concurrency" field.
|
||||
Concurrency int `json:"concurrency,omitempty"`
|
||||
// LoadFactor holds the value of the "load_factor" field.
|
||||
LoadFactor *int `json:"load_factor,omitempty"`
|
||||
// Priority holds the value of the "priority" field.
|
||||
Priority int `json:"priority,omitempty"`
|
||||
// RateMultiplier holds the value of the "rate_multiplier" field.
|
||||
@@ -143,7 +145,7 @@ func (*Account) scanValues(columns []string) ([]any, error) {
|
||||
values[i] = new(sql.NullBool)
|
||||
case account.FieldRateMultiplier:
|
||||
values[i] = new(sql.NullFloat64)
|
||||
case account.FieldID, account.FieldProxyID, account.FieldConcurrency, account.FieldPriority:
|
||||
case account.FieldID, account.FieldProxyID, account.FieldConcurrency, account.FieldLoadFactor, account.FieldPriority:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case account.FieldName, account.FieldNotes, account.FieldPlatform, account.FieldType, account.FieldStatus, account.FieldErrorMessage, account.FieldTempUnschedulableReason, account.FieldSessionWindowStatus:
|
||||
values[i] = new(sql.NullString)
|
||||
@@ -243,6 +245,13 @@ func (_m *Account) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
_m.Concurrency = int(value.Int64)
|
||||
}
|
||||
case account.FieldLoadFactor:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field load_factor", values[i])
|
||||
} else if value.Valid {
|
||||
_m.LoadFactor = new(int)
|
||||
*_m.LoadFactor = int(value.Int64)
|
||||
}
|
||||
case account.FieldPriority:
|
||||
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field priority", values[i])
|
||||
@@ -445,6 +454,11 @@ func (_m *Account) String() string {
|
||||
builder.WriteString("concurrency=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Concurrency))
|
||||
builder.WriteString(", ")
|
||||
if v := _m.LoadFactor; v != nil {
|
||||
builder.WriteString("load_factor=")
|
||||
builder.WriteString(fmt.Sprintf("%v", *v))
|
||||
}
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("priority=")
|
||||
builder.WriteString(fmt.Sprintf("%v", _m.Priority))
|
||||
builder.WriteString(", ")
|
||||
|
||||
@@ -37,6 +37,8 @@ const (
|
||||
FieldProxyID = "proxy_id"
|
||||
// FieldConcurrency holds the string denoting the concurrency field in the database.
|
||||
FieldConcurrency = "concurrency"
|
||||
// FieldLoadFactor holds the string denoting the load_factor field in the database.
|
||||
FieldLoadFactor = "load_factor"
|
||||
// FieldPriority holds the string denoting the priority field in the database.
|
||||
FieldPriority = "priority"
|
||||
// FieldRateMultiplier holds the string denoting the rate_multiplier field in the database.
|
||||
@@ -121,6 +123,7 @@ var Columns = []string{
|
||||
FieldExtra,
|
||||
FieldProxyID,
|
||||
FieldConcurrency,
|
||||
FieldLoadFactor,
|
||||
FieldPriority,
|
||||
FieldRateMultiplier,
|
||||
FieldStatus,
|
||||
@@ -250,6 +253,11 @@ func ByConcurrency(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldConcurrency, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByLoadFactor orders the results by the load_factor field.
|
||||
func ByLoadFactor(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldLoadFactor, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPriority orders the results by the priority field.
|
||||
func ByPriority(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPriority, opts...).ToFunc()
|
||||
|
||||
@@ -100,6 +100,11 @@ func Concurrency(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldEQ(FieldConcurrency, v))
|
||||
}
|
||||
|
||||
// LoadFactor applies equality check predicate on the "load_factor" field. It's identical to LoadFactorEQ.
|
||||
func LoadFactor(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldEQ(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// Priority applies equality check predicate on the "priority" field. It's identical to PriorityEQ.
|
||||
func Priority(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldEQ(FieldPriority, v))
|
||||
@@ -650,6 +655,56 @@ func ConcurrencyLTE(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldLTE(FieldConcurrency, v))
|
||||
}
|
||||
|
||||
// LoadFactorEQ applies the EQ predicate on the "load_factor" field.
|
||||
func LoadFactorEQ(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldEQ(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// LoadFactorNEQ applies the NEQ predicate on the "load_factor" field.
|
||||
func LoadFactorNEQ(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldNEQ(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// LoadFactorIn applies the In predicate on the "load_factor" field.
|
||||
func LoadFactorIn(vs ...int) predicate.Account {
|
||||
return predicate.Account(sql.FieldIn(FieldLoadFactor, vs...))
|
||||
}
|
||||
|
||||
// LoadFactorNotIn applies the NotIn predicate on the "load_factor" field.
|
||||
func LoadFactorNotIn(vs ...int) predicate.Account {
|
||||
return predicate.Account(sql.FieldNotIn(FieldLoadFactor, vs...))
|
||||
}
|
||||
|
||||
// LoadFactorGT applies the GT predicate on the "load_factor" field.
|
||||
func LoadFactorGT(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldGT(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// LoadFactorGTE applies the GTE predicate on the "load_factor" field.
|
||||
func LoadFactorGTE(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldGTE(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// LoadFactorLT applies the LT predicate on the "load_factor" field.
|
||||
func LoadFactorLT(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldLT(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// LoadFactorLTE applies the LTE predicate on the "load_factor" field.
|
||||
func LoadFactorLTE(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldLTE(FieldLoadFactor, v))
|
||||
}
|
||||
|
||||
// LoadFactorIsNil applies the IsNil predicate on the "load_factor" field.
|
||||
func LoadFactorIsNil() predicate.Account {
|
||||
return predicate.Account(sql.FieldIsNull(FieldLoadFactor))
|
||||
}
|
||||
|
||||
// LoadFactorNotNil applies the NotNil predicate on the "load_factor" field.
|
||||
func LoadFactorNotNil() predicate.Account {
|
||||
return predicate.Account(sql.FieldNotNull(FieldLoadFactor))
|
||||
}
|
||||
|
||||
// PriorityEQ applies the EQ predicate on the "priority" field.
|
||||
func PriorityEQ(v int) predicate.Account {
|
||||
return predicate.Account(sql.FieldEQ(FieldPriority, v))
|
||||
|
||||
@@ -139,6 +139,20 @@ func (_c *AccountCreate) SetNillableConcurrency(v *int) *AccountCreate {
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (_c *AccountCreate) SetLoadFactor(v int) *AccountCreate {
|
||||
_c.mutation.SetLoadFactor(v)
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetNillableLoadFactor sets the "load_factor" field if the given value is not nil.
|
||||
func (_c *AccountCreate) SetNillableLoadFactor(v *int) *AccountCreate {
|
||||
if v != nil {
|
||||
_c.SetLoadFactor(*v)
|
||||
}
|
||||
return _c
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (_c *AccountCreate) SetPriority(v int) *AccountCreate {
|
||||
_c.mutation.SetPriority(v)
|
||||
@@ -623,6 +637,10 @@ func (_c *AccountCreate) createSpec() (*Account, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(account.FieldConcurrency, field.TypeInt, value)
|
||||
_node.Concurrency = value
|
||||
}
|
||||
if value, ok := _c.mutation.LoadFactor(); ok {
|
||||
_spec.SetField(account.FieldLoadFactor, field.TypeInt, value)
|
||||
_node.LoadFactor = &value
|
||||
}
|
||||
if value, ok := _c.mutation.Priority(); ok {
|
||||
_spec.SetField(account.FieldPriority, field.TypeInt, value)
|
||||
_node.Priority = value
|
||||
@@ -936,6 +954,30 @@ func (u *AccountUpsert) AddConcurrency(v int) *AccountUpsert {
|
||||
return u
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (u *AccountUpsert) SetLoadFactor(v int) *AccountUpsert {
|
||||
u.Set(account.FieldLoadFactor, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// UpdateLoadFactor sets the "load_factor" field to the value that was provided on create.
|
||||
func (u *AccountUpsert) UpdateLoadFactor() *AccountUpsert {
|
||||
u.SetExcluded(account.FieldLoadFactor)
|
||||
return u
|
||||
}
|
||||
|
||||
// AddLoadFactor adds v to the "load_factor" field.
|
||||
func (u *AccountUpsert) AddLoadFactor(v int) *AccountUpsert {
|
||||
u.Add(account.FieldLoadFactor, v)
|
||||
return u
|
||||
}
|
||||
|
||||
// ClearLoadFactor clears the value of the "load_factor" field.
|
||||
func (u *AccountUpsert) ClearLoadFactor() *AccountUpsert {
|
||||
u.SetNull(account.FieldLoadFactor)
|
||||
return u
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (u *AccountUpsert) SetPriority(v int) *AccountUpsert {
|
||||
u.Set(account.FieldPriority, v)
|
||||
@@ -1419,6 +1461,34 @@ func (u *AccountUpsertOne) UpdateConcurrency() *AccountUpsertOne {
|
||||
})
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (u *AccountUpsertOne) SetLoadFactor(v int) *AccountUpsertOne {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.SetLoadFactor(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddLoadFactor adds v to the "load_factor" field.
|
||||
func (u *AccountUpsertOne) AddLoadFactor(v int) *AccountUpsertOne {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.AddLoadFactor(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateLoadFactor sets the "load_factor" field to the value that was provided on create.
|
||||
func (u *AccountUpsertOne) UpdateLoadFactor() *AccountUpsertOne {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.UpdateLoadFactor()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearLoadFactor clears the value of the "load_factor" field.
|
||||
func (u *AccountUpsertOne) ClearLoadFactor() *AccountUpsertOne {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.ClearLoadFactor()
|
||||
})
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (u *AccountUpsertOne) SetPriority(v int) *AccountUpsertOne {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
@@ -2113,6 +2183,34 @@ func (u *AccountUpsertBulk) UpdateConcurrency() *AccountUpsertBulk {
|
||||
})
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (u *AccountUpsertBulk) SetLoadFactor(v int) *AccountUpsertBulk {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.SetLoadFactor(v)
|
||||
})
|
||||
}
|
||||
|
||||
// AddLoadFactor adds v to the "load_factor" field.
|
||||
func (u *AccountUpsertBulk) AddLoadFactor(v int) *AccountUpsertBulk {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.AddLoadFactor(v)
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateLoadFactor sets the "load_factor" field to the value that was provided on create.
|
||||
func (u *AccountUpsertBulk) UpdateLoadFactor() *AccountUpsertBulk {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.UpdateLoadFactor()
|
||||
})
|
||||
}
|
||||
|
||||
// ClearLoadFactor clears the value of the "load_factor" field.
|
||||
func (u *AccountUpsertBulk) ClearLoadFactor() *AccountUpsertBulk {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
s.ClearLoadFactor()
|
||||
})
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (u *AccountUpsertBulk) SetPriority(v int) *AccountUpsertBulk {
|
||||
return u.Update(func(s *AccountUpsert) {
|
||||
|
||||
@@ -172,6 +172,33 @@ func (_u *AccountUpdate) AddConcurrency(v int) *AccountUpdate {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (_u *AccountUpdate) SetLoadFactor(v int) *AccountUpdate {
|
||||
_u.mutation.ResetLoadFactor()
|
||||
_u.mutation.SetLoadFactor(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableLoadFactor sets the "load_factor" field if the given value is not nil.
|
||||
func (_u *AccountUpdate) SetNillableLoadFactor(v *int) *AccountUpdate {
|
||||
if v != nil {
|
||||
_u.SetLoadFactor(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddLoadFactor adds value to the "load_factor" field.
|
||||
func (_u *AccountUpdate) AddLoadFactor(v int) *AccountUpdate {
|
||||
_u.mutation.AddLoadFactor(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearLoadFactor clears the value of the "load_factor" field.
|
||||
func (_u *AccountUpdate) ClearLoadFactor() *AccountUpdate {
|
||||
_u.mutation.ClearLoadFactor()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (_u *AccountUpdate) SetPriority(v int) *AccountUpdate {
|
||||
_u.mutation.ResetPriority()
|
||||
@@ -684,6 +711,15 @@ func (_u *AccountUpdate) sqlSave(ctx context.Context) (_node int, err error) {
|
||||
if value, ok := _u.mutation.AddedConcurrency(); ok {
|
||||
_spec.AddField(account.FieldConcurrency, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.LoadFactor(); ok {
|
||||
_spec.SetField(account.FieldLoadFactor, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedLoadFactor(); ok {
|
||||
_spec.AddField(account.FieldLoadFactor, field.TypeInt, value)
|
||||
}
|
||||
if _u.mutation.LoadFactorCleared() {
|
||||
_spec.ClearField(account.FieldLoadFactor, field.TypeInt)
|
||||
}
|
||||
if value, ok := _u.mutation.Priority(); ok {
|
||||
_spec.SetField(account.FieldPriority, field.TypeInt, value)
|
||||
}
|
||||
@@ -1063,6 +1099,33 @@ func (_u *AccountUpdateOne) AddConcurrency(v int) *AccountUpdateOne {
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (_u *AccountUpdateOne) SetLoadFactor(v int) *AccountUpdateOne {
|
||||
_u.mutation.ResetLoadFactor()
|
||||
_u.mutation.SetLoadFactor(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetNillableLoadFactor sets the "load_factor" field if the given value is not nil.
|
||||
func (_u *AccountUpdateOne) SetNillableLoadFactor(v *int) *AccountUpdateOne {
|
||||
if v != nil {
|
||||
_u.SetLoadFactor(*v)
|
||||
}
|
||||
return _u
|
||||
}
|
||||
|
||||
// AddLoadFactor adds value to the "load_factor" field.
|
||||
func (_u *AccountUpdateOne) AddLoadFactor(v int) *AccountUpdateOne {
|
||||
_u.mutation.AddLoadFactor(v)
|
||||
return _u
|
||||
}
|
||||
|
||||
// ClearLoadFactor clears the value of the "load_factor" field.
|
||||
func (_u *AccountUpdateOne) ClearLoadFactor() *AccountUpdateOne {
|
||||
_u.mutation.ClearLoadFactor()
|
||||
return _u
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (_u *AccountUpdateOne) SetPriority(v int) *AccountUpdateOne {
|
||||
_u.mutation.ResetPriority()
|
||||
@@ -1605,6 +1668,15 @@ func (_u *AccountUpdateOne) sqlSave(ctx context.Context) (_node *Account, err er
|
||||
if value, ok := _u.mutation.AddedConcurrency(); ok {
|
||||
_spec.AddField(account.FieldConcurrency, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.LoadFactor(); ok {
|
||||
_spec.SetField(account.FieldLoadFactor, field.TypeInt, value)
|
||||
}
|
||||
if value, ok := _u.mutation.AddedLoadFactor(); ok {
|
||||
_spec.AddField(account.FieldLoadFactor, field.TypeInt, value)
|
||||
}
|
||||
if _u.mutation.LoadFactorCleared() {
|
||||
_spec.ClearField(account.FieldLoadFactor, field.TypeInt)
|
||||
}
|
||||
if value, ok := _u.mutation.Priority(); ok {
|
||||
_spec.SetField(account.FieldPriority, field.TypeInt, value)
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ var (
|
||||
{Name: "credentials", Type: field.TypeJSON, SchemaType: map[string]string{"postgres": "jsonb"}},
|
||||
{Name: "extra", Type: field.TypeJSON, SchemaType: map[string]string{"postgres": "jsonb"}},
|
||||
{Name: "concurrency", Type: field.TypeInt, Default: 3},
|
||||
{Name: "load_factor", Type: field.TypeInt, Nullable: true},
|
||||
{Name: "priority", Type: field.TypeInt, Default: 50},
|
||||
{Name: "rate_multiplier", Type: field.TypeFloat64, Default: 1, SchemaType: map[string]string{"postgres": "decimal(10,4)"}},
|
||||
{Name: "status", Type: field.TypeString, Size: 20, Default: "active"},
|
||||
@@ -132,7 +133,7 @@ var (
|
||||
ForeignKeys: []*schema.ForeignKey{
|
||||
{
|
||||
Symbol: "accounts_proxies_proxy",
|
||||
Columns: []*schema.Column{AccountsColumns[27]},
|
||||
Columns: []*schema.Column{AccountsColumns[28]},
|
||||
RefColumns: []*schema.Column{ProxiesColumns[0]},
|
||||
OnDelete: schema.SetNull,
|
||||
},
|
||||
@@ -151,52 +152,52 @@ var (
|
||||
{
|
||||
Name: "account_status",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[13]},
|
||||
Columns: []*schema.Column{AccountsColumns[14]},
|
||||
},
|
||||
{
|
||||
Name: "account_proxy_id",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[27]},
|
||||
Columns: []*schema.Column{AccountsColumns[28]},
|
||||
},
|
||||
{
|
||||
Name: "account_priority",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[11]},
|
||||
Columns: []*schema.Column{AccountsColumns[12]},
|
||||
},
|
||||
{
|
||||
Name: "account_last_used_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[15]},
|
||||
Columns: []*schema.Column{AccountsColumns[16]},
|
||||
},
|
||||
{
|
||||
Name: "account_schedulable",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[18]},
|
||||
Columns: []*schema.Column{AccountsColumns[19]},
|
||||
},
|
||||
{
|
||||
Name: "account_rate_limited_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[19]},
|
||||
Columns: []*schema.Column{AccountsColumns[20]},
|
||||
},
|
||||
{
|
||||
Name: "account_rate_limit_reset_at",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[20]},
|
||||
Columns: []*schema.Column{AccountsColumns[21]},
|
||||
},
|
||||
{
|
||||
Name: "account_overload_until",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[21]},
|
||||
Columns: []*schema.Column{AccountsColumns[22]},
|
||||
},
|
||||
{
|
||||
Name: "account_platform_priority",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[6], AccountsColumns[11]},
|
||||
Columns: []*schema.Column{AccountsColumns[6], AccountsColumns[12]},
|
||||
},
|
||||
{
|
||||
Name: "account_priority_status",
|
||||
Unique: false,
|
||||
Columns: []*schema.Column{AccountsColumns[11], AccountsColumns[13]},
|
||||
Columns: []*schema.Column{AccountsColumns[12], AccountsColumns[14]},
|
||||
},
|
||||
{
|
||||
Name: "account_deleted_at",
|
||||
|
||||
@@ -2260,6 +2260,8 @@ type AccountMutation struct {
|
||||
extra *map[string]interface{}
|
||||
concurrency *int
|
||||
addconcurrency *int
|
||||
load_factor *int
|
||||
addload_factor *int
|
||||
priority *int
|
||||
addpriority *int
|
||||
rate_multiplier *float64
|
||||
@@ -2845,6 +2847,76 @@ func (m *AccountMutation) ResetConcurrency() {
|
||||
m.addconcurrency = nil
|
||||
}
|
||||
|
||||
// SetLoadFactor sets the "load_factor" field.
|
||||
func (m *AccountMutation) SetLoadFactor(i int) {
|
||||
m.load_factor = &i
|
||||
m.addload_factor = nil
|
||||
}
|
||||
|
||||
// LoadFactor returns the value of the "load_factor" field in the mutation.
|
||||
func (m *AccountMutation) LoadFactor() (r int, exists bool) {
|
||||
v := m.load_factor
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldLoadFactor returns the old "load_factor" field's value of the Account entity.
|
||||
// If the Account object wasn't provided to the builder, the object is fetched from the database.
|
||||
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
|
||||
func (m *AccountMutation) OldLoadFactor(ctx context.Context) (v *int, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldLoadFactor is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldLoadFactor requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldLoadFactor: %w", err)
|
||||
}
|
||||
return oldValue.LoadFactor, nil
|
||||
}
|
||||
|
||||
// AddLoadFactor adds i to the "load_factor" field.
|
||||
func (m *AccountMutation) AddLoadFactor(i int) {
|
||||
if m.addload_factor != nil {
|
||||
*m.addload_factor += i
|
||||
} else {
|
||||
m.addload_factor = &i
|
||||
}
|
||||
}
|
||||
|
||||
// AddedLoadFactor returns the value that was added to the "load_factor" field in this mutation.
|
||||
func (m *AccountMutation) AddedLoadFactor() (r int, exists bool) {
|
||||
v := m.addload_factor
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ClearLoadFactor clears the value of the "load_factor" field.
|
||||
func (m *AccountMutation) ClearLoadFactor() {
|
||||
m.load_factor = nil
|
||||
m.addload_factor = nil
|
||||
m.clearedFields[account.FieldLoadFactor] = struct{}{}
|
||||
}
|
||||
|
||||
// LoadFactorCleared returns if the "load_factor" field was cleared in this mutation.
|
||||
func (m *AccountMutation) LoadFactorCleared() bool {
|
||||
_, ok := m.clearedFields[account.FieldLoadFactor]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetLoadFactor resets all changes to the "load_factor" field.
|
||||
func (m *AccountMutation) ResetLoadFactor() {
|
||||
m.load_factor = nil
|
||||
m.addload_factor = nil
|
||||
delete(m.clearedFields, account.FieldLoadFactor)
|
||||
}
|
||||
|
||||
// SetPriority sets the "priority" field.
|
||||
func (m *AccountMutation) SetPriority(i int) {
|
||||
m.priority = &i
|
||||
@@ -3773,7 +3845,7 @@ func (m *AccountMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *AccountMutation) Fields() []string {
|
||||
fields := make([]string, 0, 27)
|
||||
fields := make([]string, 0, 28)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, account.FieldCreatedAt)
|
||||
}
|
||||
@@ -3807,6 +3879,9 @@ func (m *AccountMutation) Fields() []string {
|
||||
if m.concurrency != nil {
|
||||
fields = append(fields, account.FieldConcurrency)
|
||||
}
|
||||
if m.load_factor != nil {
|
||||
fields = append(fields, account.FieldLoadFactor)
|
||||
}
|
||||
if m.priority != nil {
|
||||
fields = append(fields, account.FieldPriority)
|
||||
}
|
||||
@@ -3885,6 +3960,8 @@ func (m *AccountMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.ProxyID()
|
||||
case account.FieldConcurrency:
|
||||
return m.Concurrency()
|
||||
case account.FieldLoadFactor:
|
||||
return m.LoadFactor()
|
||||
case account.FieldPriority:
|
||||
return m.Priority()
|
||||
case account.FieldRateMultiplier:
|
||||
@@ -3948,6 +4025,8 @@ func (m *AccountMutation) OldField(ctx context.Context, name string) (ent.Value,
|
||||
return m.OldProxyID(ctx)
|
||||
case account.FieldConcurrency:
|
||||
return m.OldConcurrency(ctx)
|
||||
case account.FieldLoadFactor:
|
||||
return m.OldLoadFactor(ctx)
|
||||
case account.FieldPriority:
|
||||
return m.OldPriority(ctx)
|
||||
case account.FieldRateMultiplier:
|
||||
@@ -4066,6 +4145,13 @@ func (m *AccountMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetConcurrency(v)
|
||||
return nil
|
||||
case account.FieldLoadFactor:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetLoadFactor(v)
|
||||
return nil
|
||||
case account.FieldPriority:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
@@ -4189,6 +4275,9 @@ func (m *AccountMutation) AddedFields() []string {
|
||||
if m.addconcurrency != nil {
|
||||
fields = append(fields, account.FieldConcurrency)
|
||||
}
|
||||
if m.addload_factor != nil {
|
||||
fields = append(fields, account.FieldLoadFactor)
|
||||
}
|
||||
if m.addpriority != nil {
|
||||
fields = append(fields, account.FieldPriority)
|
||||
}
|
||||
@@ -4205,6 +4294,8 @@ func (m *AccountMutation) AddedField(name string) (ent.Value, bool) {
|
||||
switch name {
|
||||
case account.FieldConcurrency:
|
||||
return m.AddedConcurrency()
|
||||
case account.FieldLoadFactor:
|
||||
return m.AddedLoadFactor()
|
||||
case account.FieldPriority:
|
||||
return m.AddedPriority()
|
||||
case account.FieldRateMultiplier:
|
||||
@@ -4225,6 +4316,13 @@ func (m *AccountMutation) AddField(name string, value ent.Value) error {
|
||||
}
|
||||
m.AddConcurrency(v)
|
||||
return nil
|
||||
case account.FieldLoadFactor:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddLoadFactor(v)
|
||||
return nil
|
||||
case account.FieldPriority:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
@@ -4256,6 +4354,9 @@ func (m *AccountMutation) ClearedFields() []string {
|
||||
if m.FieldCleared(account.FieldProxyID) {
|
||||
fields = append(fields, account.FieldProxyID)
|
||||
}
|
||||
if m.FieldCleared(account.FieldLoadFactor) {
|
||||
fields = append(fields, account.FieldLoadFactor)
|
||||
}
|
||||
if m.FieldCleared(account.FieldErrorMessage) {
|
||||
fields = append(fields, account.FieldErrorMessage)
|
||||
}
|
||||
@@ -4312,6 +4413,9 @@ func (m *AccountMutation) ClearField(name string) error {
|
||||
case account.FieldProxyID:
|
||||
m.ClearProxyID()
|
||||
return nil
|
||||
case account.FieldLoadFactor:
|
||||
m.ClearLoadFactor()
|
||||
return nil
|
||||
case account.FieldErrorMessage:
|
||||
m.ClearErrorMessage()
|
||||
return nil
|
||||
@@ -4386,6 +4490,9 @@ func (m *AccountMutation) ResetField(name string) error {
|
||||
case account.FieldConcurrency:
|
||||
m.ResetConcurrency()
|
||||
return nil
|
||||
case account.FieldLoadFactor:
|
||||
m.ResetLoadFactor()
|
||||
return nil
|
||||
case account.FieldPriority:
|
||||
m.ResetPriority()
|
||||
return nil
|
||||
@@ -10228,7 +10335,7 @@ func (m *GroupMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *GroupMutation) Fields() []string {
|
||||
fields := make([]string, 0, 30)
|
||||
fields := make([]string, 0, 31)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, group.FieldCreatedAt)
|
||||
}
|
||||
|
||||
@@ -212,29 +212,29 @@ func init() {
|
||||
// account.DefaultConcurrency holds the default value on creation for the concurrency field.
|
||||
account.DefaultConcurrency = accountDescConcurrency.Default.(int)
|
||||
// accountDescPriority is the schema descriptor for priority field.
|
||||
accountDescPriority := accountFields[8].Descriptor()
|
||||
accountDescPriority := accountFields[9].Descriptor()
|
||||
// account.DefaultPriority holds the default value on creation for the priority field.
|
||||
account.DefaultPriority = accountDescPriority.Default.(int)
|
||||
// accountDescRateMultiplier is the schema descriptor for rate_multiplier field.
|
||||
accountDescRateMultiplier := accountFields[9].Descriptor()
|
||||
accountDescRateMultiplier := accountFields[10].Descriptor()
|
||||
// account.DefaultRateMultiplier holds the default value on creation for the rate_multiplier field.
|
||||
account.DefaultRateMultiplier = accountDescRateMultiplier.Default.(float64)
|
||||
// accountDescStatus is the schema descriptor for status field.
|
||||
accountDescStatus := accountFields[10].Descriptor()
|
||||
accountDescStatus := accountFields[11].Descriptor()
|
||||
// account.DefaultStatus holds the default value on creation for the status field.
|
||||
account.DefaultStatus = accountDescStatus.Default.(string)
|
||||
// account.StatusValidator is a validator for the "status" field. It is called by the builders before save.
|
||||
account.StatusValidator = accountDescStatus.Validators[0].(func(string) error)
|
||||
// accountDescAutoPauseOnExpired is the schema descriptor for auto_pause_on_expired field.
|
||||
accountDescAutoPauseOnExpired := accountFields[14].Descriptor()
|
||||
accountDescAutoPauseOnExpired := accountFields[15].Descriptor()
|
||||
// account.DefaultAutoPauseOnExpired holds the default value on creation for the auto_pause_on_expired field.
|
||||
account.DefaultAutoPauseOnExpired = accountDescAutoPauseOnExpired.Default.(bool)
|
||||
// accountDescSchedulable is the schema descriptor for schedulable field.
|
||||
accountDescSchedulable := accountFields[15].Descriptor()
|
||||
accountDescSchedulable := accountFields[16].Descriptor()
|
||||
// account.DefaultSchedulable holds the default value on creation for the schedulable field.
|
||||
account.DefaultSchedulable = accountDescSchedulable.Default.(bool)
|
||||
// accountDescSessionWindowStatus is the schema descriptor for session_window_status field.
|
||||
accountDescSessionWindowStatus := accountFields[23].Descriptor()
|
||||
accountDescSessionWindowStatus := accountFields[24].Descriptor()
|
||||
// account.SessionWindowStatusValidator is a validator for the "session_window_status" field. It is called by the builders before save.
|
||||
account.SessionWindowStatusValidator = accountDescSessionWindowStatus.Validators[0].(func(string) error)
|
||||
accountgroupFields := schema.AccountGroup{}.Fields()
|
||||
|
||||
@@ -97,6 +97,8 @@ func (Account) Fields() []ent.Field {
|
||||
field.Int("concurrency").
|
||||
Default(3),
|
||||
|
||||
field.Int("load_factor").Optional().Nillable(),
|
||||
|
||||
// priority: 账户优先级,数值越小优先级越高
|
||||
// 调度器会优先使用高优先级的账户
|
||||
field.Int("priority").
|
||||
|
||||
@@ -94,6 +94,10 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
|
||||
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||
github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U=
|
||||
github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
|
||||
github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g=
|
||||
github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg=
|
||||
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
|
||||
@@ -178,6 +182,7 @@ github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.7.0 h1:JxUKI6+CVBgCO2WToKy/nQk0sS+amI9z9EjVmdaocj4=
|
||||
@@ -197,6 +202,8 @@ github.com/icholy/digest v1.1.0 h1:HfGg9Irj7i+IX1o1QAmPfIBNu/Q5A5Tu3n/MED9k9H4=
|
||||
github.com/icholy/digest v1.1.0/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y=
|
||||
github.com/imroc/req/v3 v3.57.0 h1:LMTUjNRUybUkTPn8oJDq8Kg3JRBOBTcnDhKu7mzupKI=
|
||||
github.com/imroc/req/v3 v3.57.0/go.mod h1:JL62ey1nvSLq81HORNcosvlf7SxZStONNqOprg0Pz00=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
@@ -232,6 +239,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
|
||||
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mdelapenya/tlscert v0.2.0 h1:7H81W6Z/4weDvZBNOfQte5GpIMo0lGYEeWbkGp5LJHI=
|
||||
@@ -265,6 +274,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
|
||||
@@ -320,6 +331,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
|
||||
@@ -102,6 +102,7 @@ type CreateAccountRequest struct {
|
||||
Concurrency int `json:"concurrency"`
|
||||
Priority int `json:"priority"`
|
||||
RateMultiplier *float64 `json:"rate_multiplier"`
|
||||
LoadFactor *int `json:"load_factor"`
|
||||
GroupIDs []int64 `json:"group_ids"`
|
||||
ExpiresAt *int64 `json:"expires_at"`
|
||||
AutoPauseOnExpired *bool `json:"auto_pause_on_expired"`
|
||||
@@ -120,6 +121,7 @@ type UpdateAccountRequest struct {
|
||||
Concurrency *int `json:"concurrency"`
|
||||
Priority *int `json:"priority"`
|
||||
RateMultiplier *float64 `json:"rate_multiplier"`
|
||||
LoadFactor *int `json:"load_factor"`
|
||||
Status string `json:"status" binding:"omitempty,oneof=active inactive"`
|
||||
GroupIDs *[]int64 `json:"group_ids"`
|
||||
ExpiresAt *int64 `json:"expires_at"`
|
||||
@@ -135,6 +137,7 @@ type BulkUpdateAccountsRequest struct {
|
||||
Concurrency *int `json:"concurrency"`
|
||||
Priority *int `json:"priority"`
|
||||
RateMultiplier *float64 `json:"rate_multiplier"`
|
||||
LoadFactor *int `json:"load_factor"`
|
||||
Status string `json:"status" binding:"omitempty,oneof=active inactive error"`
|
||||
Schedulable *bool `json:"schedulable"`
|
||||
GroupIDs *[]int64 `json:"group_ids"`
|
||||
@@ -506,6 +509,7 @@ func (h *AccountHandler) Create(c *gin.Context) {
|
||||
Concurrency: req.Concurrency,
|
||||
Priority: req.Priority,
|
||||
RateMultiplier: req.RateMultiplier,
|
||||
LoadFactor: req.LoadFactor,
|
||||
GroupIDs: req.GroupIDs,
|
||||
ExpiresAt: req.ExpiresAt,
|
||||
AutoPauseOnExpired: req.AutoPauseOnExpired,
|
||||
@@ -575,6 +579,7 @@ func (h *AccountHandler) Update(c *gin.Context) {
|
||||
Concurrency: req.Concurrency, // 指针类型,nil 表示未提供
|
||||
Priority: req.Priority, // 指针类型,nil 表示未提供
|
||||
RateMultiplier: req.RateMultiplier,
|
||||
LoadFactor: req.LoadFactor,
|
||||
Status: req.Status,
|
||||
GroupIDs: req.GroupIDs,
|
||||
ExpiresAt: req.ExpiresAt,
|
||||
@@ -1101,6 +1106,7 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
|
||||
req.Concurrency != nil ||
|
||||
req.Priority != nil ||
|
||||
req.RateMultiplier != nil ||
|
||||
req.LoadFactor != nil ||
|
||||
req.Status != "" ||
|
||||
req.Schedulable != nil ||
|
||||
req.GroupIDs != nil ||
|
||||
@@ -1119,6 +1125,7 @@ func (h *AccountHandler) BulkUpdate(c *gin.Context) {
|
||||
Concurrency: req.Concurrency,
|
||||
Priority: req.Priority,
|
||||
RateMultiplier: req.RateMultiplier,
|
||||
LoadFactor: req.LoadFactor,
|
||||
Status: req.Status,
|
||||
Schedulable: req.Schedulable,
|
||||
GroupIDs: req.GroupIDs,
|
||||
|
||||
@@ -184,6 +184,7 @@ func AccountFromServiceShallow(a *service.Account) *Account {
|
||||
Extra: a.Extra,
|
||||
ProxyID: a.ProxyID,
|
||||
Concurrency: a.Concurrency,
|
||||
LoadFactor: a.LoadFactor,
|
||||
Priority: a.Priority,
|
||||
RateMultiplier: a.BillingRateMultiplier(),
|
||||
Status: a.Status,
|
||||
|
||||
@@ -133,6 +133,7 @@ type Account struct {
|
||||
Extra map[string]any `json:"extra"`
|
||||
ProxyID *int64 `json:"proxy_id"`
|
||||
Concurrency int `json:"concurrency"`
|
||||
LoadFactor *int `json:"load_factor,omitempty"`
|
||||
Priority int `json:"priority"`
|
||||
RateMultiplier float64 `json:"rate_multiplier"`
|
||||
Status string `json:"status"`
|
||||
|
||||
@@ -337,9 +337,6 @@ func (s *stubUsageLogRepo) GetModelStatsWithFilters(ctx context.Context, startTi
|
||||
func (s *stubUsageLogRepo) GetGroupStatsWithFilters(ctx context.Context, startTime, endTime time.Time, userID, apiKeyID, accountID, groupID int64, requestType *int16, stream *bool, billingType *int8) ([]usagestats.GroupStat, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *stubUsageLogRepo) GetGroupStatsWithFilters(ctx context.Context, startTime, endTime time.Time, userID, apiKeyID, accountID, groupID int64, stream *bool, billingType *int8) ([]usagestats.GroupStat, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (s *stubUsageLogRepo) GetAPIKeyUsageTrend(ctx context.Context, startTime, endTime time.Time, granularity string, limit int) ([]usagestats.APIKeyUsageTrendPoint, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -84,6 +84,9 @@ func (r *accountRepository) Create(ctx context.Context, account *service.Account
|
||||
if account.RateMultiplier != nil {
|
||||
builder.SetRateMultiplier(*account.RateMultiplier)
|
||||
}
|
||||
if account.LoadFactor != nil {
|
||||
builder.SetLoadFactor(*account.LoadFactor)
|
||||
}
|
||||
|
||||
if account.ProxyID != nil {
|
||||
builder.SetProxyID(*account.ProxyID)
|
||||
@@ -318,6 +321,11 @@ func (r *accountRepository) Update(ctx context.Context, account *service.Account
|
||||
if account.RateMultiplier != nil {
|
||||
builder.SetRateMultiplier(*account.RateMultiplier)
|
||||
}
|
||||
if account.LoadFactor != nil {
|
||||
builder.SetLoadFactor(*account.LoadFactor)
|
||||
} else {
|
||||
builder.ClearLoadFactor()
|
||||
}
|
||||
|
||||
if account.ProxyID != nil {
|
||||
builder.SetProxyID(*account.ProxyID)
|
||||
@@ -1205,6 +1213,15 @@ func (r *accountRepository) BulkUpdate(ctx context.Context, ids []int64, updates
|
||||
args = append(args, *updates.RateMultiplier)
|
||||
idx++
|
||||
}
|
||||
if updates.LoadFactor != nil {
|
||||
if *updates.LoadFactor <= 0 {
|
||||
setClauses = append(setClauses, "load_factor = NULL")
|
||||
} else {
|
||||
setClauses = append(setClauses, "load_factor = $"+itoa(idx))
|
||||
args = append(args, *updates.LoadFactor)
|
||||
idx++
|
||||
}
|
||||
}
|
||||
if updates.Status != nil {
|
||||
setClauses = append(setClauses, "status = $"+itoa(idx))
|
||||
args = append(args, *updates.Status)
|
||||
@@ -1527,6 +1544,7 @@ func accountEntityToService(m *dbent.Account) *service.Account {
|
||||
Concurrency: m.Concurrency,
|
||||
Priority: m.Priority,
|
||||
RateMultiplier: &rateMultiplier,
|
||||
LoadFactor: m.LoadFactor,
|
||||
Status: m.Status,
|
||||
ErrorMessage: derefString(m.ErrorMessage),
|
||||
LastUsedAt: m.LastUsedAt,
|
||||
|
||||
@@ -1096,6 +1096,14 @@ func (s *stubAccountRepo) UpdateExtra(ctx context.Context, id int64, updates map
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (s *stubAccountRepo) IncrementQuotaUsed(ctx context.Context, id int64, amount float64) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (s *stubAccountRepo) ResetQuotaUsed(ctx context.Context, id int64) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (s *stubAccountRepo) BulkUpdate(ctx context.Context, ids []int64, updates service.AccountBulkUpdate) (int64, error) {
|
||||
s.bulkUpdateIDs = append([]int64{}, ids...)
|
||||
return int64(len(ids)), nil
|
||||
@@ -1617,10 +1625,6 @@ func (r *stubUsageLogRepo) GetGroupStatsWithFilters(ctx context.Context, startTi
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (r *stubUsageLogRepo) GetGroupStatsWithFilters(ctx context.Context, startTime, endTime time.Time, userID, apiKeyID, accountID, groupID int64, stream *bool, billingType *int8) ([]usagestats.GroupStat, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (r *stubUsageLogRepo) GetAPIKeyUsageTrend(ctx context.Context, startTime, endTime time.Time, granularity string, limit int) ([]usagestats.APIKeyUsageTrendPoint, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
//go:build unit
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExtractOrigin(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"empty string", "", ""},
|
||||
{"whitespace only", " ", ""},
|
||||
{"valid https", "https://pay.example.com/checkout", "https://pay.example.com"},
|
||||
{"valid http", "http://pay.example.com/checkout", "http://pay.example.com"},
|
||||
{"https with port", "https://pay.example.com:8443/checkout", "https://pay.example.com:8443"},
|
||||
{"protocol-relative //host", "//pay.example.com/path", ""},
|
||||
{"no scheme", "pay.example.com/path", ""},
|
||||
{"ftp scheme rejected", "ftp://pay.example.com/file", ""},
|
||||
{"empty host after parse", "https:///path", ""},
|
||||
{"invalid url", "://bad url", ""},
|
||||
{"only scheme", "https://", ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := extractOrigin(tt.input)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ type Account struct {
|
||||
// RateMultiplier 账号计费倍率(>=0,允许 0 表示该账号计费为 0)。
|
||||
// 使用指针用于兼容旧版本调度缓存(Redis)中缺字段的情况:nil 表示按 1.0 处理。
|
||||
RateMultiplier *float64
|
||||
LoadFactor *int // 调度负载因子;nil 表示使用 Concurrency
|
||||
Status string
|
||||
ErrorMessage string
|
||||
LastUsedAt *time.Time
|
||||
@@ -88,6 +89,19 @@ func (a *Account) BillingRateMultiplier() float64 {
|
||||
return *a.RateMultiplier
|
||||
}
|
||||
|
||||
func (a *Account) EffectiveLoadFactor() int {
|
||||
if a == nil {
|
||||
return 1
|
||||
}
|
||||
if a.LoadFactor != nil && *a.LoadFactor > 0 {
|
||||
return *a.LoadFactor
|
||||
}
|
||||
if a.Concurrency > 0 {
|
||||
return a.Concurrency
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
func (a *Account) IsSchedulable() bool {
|
||||
if !a.IsActive() || !a.Schedulable {
|
||||
return false
|
||||
|
||||
42
backend/internal/service/account_load_factor_test.go
Normal file
42
backend/internal/service/account_load_factor_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEffectiveLoadFactor_NilAccount(t *testing.T) {
|
||||
var a *Account
|
||||
require.Equal(t, 1, a.EffectiveLoadFactor())
|
||||
}
|
||||
|
||||
func TestEffectiveLoadFactor_NilLoadFactor_PositiveConcurrency(t *testing.T) {
|
||||
a := &Account{Concurrency: 5}
|
||||
require.Equal(t, 5, a.EffectiveLoadFactor())
|
||||
}
|
||||
|
||||
func TestEffectiveLoadFactor_NilLoadFactor_ZeroConcurrency(t *testing.T) {
|
||||
a := &Account{Concurrency: 0}
|
||||
require.Equal(t, 1, a.EffectiveLoadFactor())
|
||||
}
|
||||
|
||||
func TestEffectiveLoadFactor_PositiveLoadFactor(t *testing.T) {
|
||||
a := &Account{Concurrency: 5, LoadFactor: intPtr(20)}
|
||||
require.Equal(t, 20, a.EffectiveLoadFactor())
|
||||
}
|
||||
|
||||
func TestEffectiveLoadFactor_ZeroLoadFactor_FallbackToConcurrency(t *testing.T) {
|
||||
a := &Account{Concurrency: 5, LoadFactor: intPtr(0)}
|
||||
require.Equal(t, 5, a.EffectiveLoadFactor())
|
||||
}
|
||||
|
||||
func TestEffectiveLoadFactor_NegativeLoadFactor_FallbackToConcurrency(t *testing.T) {
|
||||
a := &Account{Concurrency: 3, LoadFactor: intPtr(-1)}
|
||||
require.Equal(t, 3, a.EffectiveLoadFactor())
|
||||
}
|
||||
|
||||
func TestEffectiveLoadFactor_ZeroLoadFactor_ZeroConcurrency(t *testing.T) {
|
||||
a := &Account{Concurrency: 0, LoadFactor: intPtr(0)}
|
||||
require.Equal(t, 1, a.EffectiveLoadFactor())
|
||||
}
|
||||
@@ -82,6 +82,7 @@ type AccountBulkUpdate struct {
|
||||
Concurrency *int
|
||||
Priority *int
|
||||
RateMultiplier *float64
|
||||
LoadFactor *int
|
||||
Status *string
|
||||
Schedulable *bool
|
||||
Credentials map[string]any
|
||||
|
||||
@@ -198,6 +198,7 @@ type CreateAccountInput struct {
|
||||
Concurrency int
|
||||
Priority int
|
||||
RateMultiplier *float64 // 账号计费倍率(>=0,允许 0)
|
||||
LoadFactor *int
|
||||
GroupIDs []int64
|
||||
ExpiresAt *int64
|
||||
AutoPauseOnExpired *bool
|
||||
@@ -218,6 +219,7 @@ type UpdateAccountInput struct {
|
||||
Concurrency *int // 使用指针区分"未提供"和"设置为0"
|
||||
Priority *int // 使用指针区分"未提供"和"设置为0"
|
||||
RateMultiplier *float64 // 账号计费倍率(>=0,允许 0)
|
||||
LoadFactor *int
|
||||
Status string
|
||||
GroupIDs *[]int64
|
||||
ExpiresAt *int64
|
||||
@@ -233,6 +235,7 @@ type BulkUpdateAccountsInput struct {
|
||||
Concurrency *int
|
||||
Priority *int
|
||||
RateMultiplier *float64 // 账号计费倍率(>=0,允许 0)
|
||||
LoadFactor *int
|
||||
Status string
|
||||
Schedulable *bool
|
||||
GroupIDs *[]int64
|
||||
@@ -1433,6 +1436,9 @@ func (s *adminServiceImpl) CreateAccount(ctx context.Context, input *CreateAccou
|
||||
}
|
||||
account.RateMultiplier = input.RateMultiplier
|
||||
}
|
||||
if input.LoadFactor != nil && *input.LoadFactor > 0 {
|
||||
account.LoadFactor = input.LoadFactor
|
||||
}
|
||||
if err := s.accountRepo.Create(ctx, account); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1507,6 +1513,13 @@ func (s *adminServiceImpl) UpdateAccount(ctx context.Context, id int64, input *U
|
||||
}
|
||||
account.RateMultiplier = input.RateMultiplier
|
||||
}
|
||||
if input.LoadFactor != nil {
|
||||
if *input.LoadFactor <= 0 {
|
||||
account.LoadFactor = nil // 0 或负数表示清除
|
||||
} else {
|
||||
account.LoadFactor = input.LoadFactor
|
||||
}
|
||||
}
|
||||
if input.Status != "" {
|
||||
account.Status = input.Status
|
||||
}
|
||||
@@ -1640,6 +1653,9 @@ func (s *adminServiceImpl) BulkUpdateAccounts(ctx context.Context, input *BulkUp
|
||||
if input.RateMultiplier != nil {
|
||||
repoUpdates.RateMultiplier = input.RateMultiplier
|
||||
}
|
||||
if input.LoadFactor != nil {
|
||||
repoUpdates.LoadFactor = input.LoadFactor
|
||||
}
|
||||
if input.Status != "" {
|
||||
repoUpdates.Status = &input.Status
|
||||
}
|
||||
|
||||
@@ -1322,7 +1322,7 @@ func (s *GatewayService) SelectAccountWithLoadAwareness(ctx context.Context, gro
|
||||
for _, acc := range routingCandidates {
|
||||
routingLoads = append(routingLoads, AccountWithConcurrency{
|
||||
ID: acc.ID,
|
||||
MaxConcurrency: acc.Concurrency,
|
||||
MaxConcurrency: acc.EffectiveLoadFactor(),
|
||||
})
|
||||
}
|
||||
routingLoadMap, _ := s.concurrencyService.GetAccountsLoadBatch(ctx, routingLoads)
|
||||
@@ -1515,7 +1515,7 @@ func (s *GatewayService) SelectAccountWithLoadAwareness(ctx context.Context, gro
|
||||
for _, acc := range candidates {
|
||||
accountLoads = append(accountLoads, AccountWithConcurrency{
|
||||
ID: acc.ID,
|
||||
MaxConcurrency: acc.Concurrency,
|
||||
MaxConcurrency: acc.EffectiveLoadFactor(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -590,7 +590,7 @@ func (s *defaultOpenAIAccountScheduler) selectByLoadBalance(
|
||||
filtered = append(filtered, account)
|
||||
loadReq = append(loadReq, AccountWithConcurrency{
|
||||
ID: account.ID,
|
||||
MaxConcurrency: account.Concurrency,
|
||||
MaxConcurrency: account.EffectiveLoadFactor(),
|
||||
})
|
||||
}
|
||||
if len(filtered) == 0 {
|
||||
|
||||
@@ -1250,7 +1250,7 @@ func (s *OpenAIGatewayService) SelectAccountWithLoadAwareness(ctx context.Contex
|
||||
for _, acc := range candidates {
|
||||
accountLoads = append(accountLoads, AccountWithConcurrency{
|
||||
ID: acc.ID,
|
||||
MaxConcurrency: acc.Concurrency,
|
||||
MaxConcurrency: acc.EffectiveLoadFactor(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -64,8 +64,9 @@ func (s *OpsService) getAccountsLoadMapBestEffort(ctx context.Context, accounts
|
||||
if acc.ID <= 0 {
|
||||
continue
|
||||
}
|
||||
if prev, ok := unique[acc.ID]; !ok || acc.Concurrency > prev {
|
||||
unique[acc.ID] = acc.Concurrency
|
||||
lf := acc.EffectiveLoadFactor()
|
||||
if prev, ok := unique[acc.ID]; !ok || lf > prev {
|
||||
unique[acc.ID] = lf
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -389,13 +389,9 @@ func (c *OpsMetricsCollector) collectConcurrencyQueueDepth(parentCtx context.Con
|
||||
if acc.ID <= 0 {
|
||||
continue
|
||||
}
|
||||
maxConc := acc.Concurrency
|
||||
if maxConc < 0 {
|
||||
maxConc = 0
|
||||
}
|
||||
batch = append(batch, AccountWithConcurrency{
|
||||
ID: acc.ID,
|
||||
MaxConcurrency: maxConc,
|
||||
MaxConcurrency: acc.EffectiveLoadFactor(),
|
||||
})
|
||||
}
|
||||
if len(batch) == 0 {
|
||||
|
||||
1
backend/migrations/067_add_account_load_factor.sql
Normal file
1
backend/migrations/067_add_account_load_factor.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE accounts ADD COLUMN IF NOT EXISTS load_factor INTEGER;
|
||||
@@ -469,7 +469,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Concurrency & Priority -->
|
||||
<div class="grid grid-cols-2 gap-4 border-t border-gray-200 pt-4 dark:border-dark-600 lg:grid-cols-3">
|
||||
<div class="grid grid-cols-2 gap-4 border-t border-gray-200 pt-4 dark:border-dark-600 lg:grid-cols-4">
|
||||
<div>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<label
|
||||
@@ -498,6 +498,35 @@
|
||||
aria-labelledby="bulk-edit-concurrency-label"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<label
|
||||
id="bulk-edit-load-factor-label"
|
||||
class="input-label mb-0"
|
||||
for="bulk-edit-load-factor-enabled"
|
||||
>
|
||||
{{ t('admin.accounts.loadFactor') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="enableLoadFactor"
|
||||
id="bulk-edit-load-factor-enabled"
|
||||
type="checkbox"
|
||||
aria-controls="bulk-edit-load-factor"
|
||||
class="rounded border-gray-300 text-primary-600 focus:ring-primary-500"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
v-model.number="loadFactor"
|
||||
id="bulk-edit-load-factor"
|
||||
type="number"
|
||||
min="1"
|
||||
:disabled="!enableLoadFactor"
|
||||
class="input"
|
||||
:class="!enableLoadFactor && 'cursor-not-allowed opacity-50'"
|
||||
aria-labelledby="bulk-edit-load-factor-label"
|
||||
/>
|
||||
<p class="input-hint">{{ t('admin.accounts.loadFactorHint') }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<label
|
||||
@@ -869,6 +898,7 @@ const enableCustomErrorCodes = ref(false)
|
||||
const enableInterceptWarmup = ref(false)
|
||||
const enableProxy = ref(false)
|
||||
const enableConcurrency = ref(false)
|
||||
const enableLoadFactor = ref(false)
|
||||
const enablePriority = ref(false)
|
||||
const enableRateMultiplier = ref(false)
|
||||
const enableStatus = ref(false)
|
||||
@@ -889,6 +919,7 @@ const customErrorCodeInput = ref<number | null>(null)
|
||||
const interceptWarmupRequests = ref(false)
|
||||
const proxyId = ref<number | null>(null)
|
||||
const concurrency = ref(1)
|
||||
const loadFactor = ref<number | null>(null)
|
||||
const priority = ref(1)
|
||||
const rateMultiplier = ref(1)
|
||||
const status = ref<'active' | 'inactive'>('active')
|
||||
@@ -1195,6 +1226,10 @@ const buildUpdatePayload = (): Record<string, unknown> | null => {
|
||||
updates.concurrency = concurrency.value
|
||||
}
|
||||
|
||||
if (enableLoadFactor.value) {
|
||||
updates.load_factor = loadFactor.value
|
||||
}
|
||||
|
||||
if (enablePriority.value) {
|
||||
updates.priority = priority.value
|
||||
}
|
||||
@@ -1340,6 +1375,7 @@ const handleSubmit = async () => {
|
||||
enableInterceptWarmup.value ||
|
||||
enableProxy.value ||
|
||||
enableConcurrency.value ||
|
||||
enableLoadFactor.value ||
|
||||
enablePriority.value ||
|
||||
enableRateMultiplier.value ||
|
||||
enableStatus.value ||
|
||||
@@ -1430,6 +1466,7 @@ watch(
|
||||
enableInterceptWarmup.value = false
|
||||
enableProxy.value = false
|
||||
enableConcurrency.value = false
|
||||
enableLoadFactor.value = false
|
||||
enablePriority.value = false
|
||||
enableRateMultiplier.value = false
|
||||
enableStatus.value = false
|
||||
@@ -1446,6 +1483,7 @@ watch(
|
||||
interceptWarmupRequests.value = false
|
||||
proxyId.value = null
|
||||
concurrency.value = 1
|
||||
loadFactor.value = null
|
||||
priority.value = 1
|
||||
rateMultiplier.value = 1
|
||||
status.value = 'active'
|
||||
|
||||
@@ -1752,11 +1752,17 @@
|
||||
<ProxySelector v-model="form.proxy_id" :proxies="proxies" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 lg:grid-cols-3">
|
||||
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.concurrency') }}</label>
|
||||
<input v-model.number="form.concurrency" type="number" min="1" class="input" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.loadFactor') }}</label>
|
||||
<input v-model.number="form.load_factor" type="number" min="1"
|
||||
class="input" :placeholder="String(form.concurrency || 1)" />
|
||||
<p class="input-hint">{{ t('admin.accounts.loadFactorHint') }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.priority') }}</label>
|
||||
<input
|
||||
@@ -2632,6 +2638,7 @@ const form = reactive({
|
||||
credentials: {} as Record<string, unknown>,
|
||||
proxy_id: null as number | null,
|
||||
concurrency: 10,
|
||||
load_factor: null as number | null,
|
||||
priority: 1,
|
||||
rate_multiplier: 1,
|
||||
group_ids: [] as number[],
|
||||
@@ -3111,6 +3118,7 @@ const resetForm = () => {
|
||||
form.credentials = {}
|
||||
form.proxy_id = null
|
||||
form.concurrency = 10
|
||||
form.load_factor = null
|
||||
form.priority = 1
|
||||
form.rate_multiplier = 1
|
||||
form.group_ids = []
|
||||
@@ -3480,6 +3488,7 @@ const handleImportAccessToken = async (accessTokenInput: string) => {
|
||||
extra: soraExtra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3544,6 +3553,7 @@ const createAccountAndFinish = async (
|
||||
extra: finalExtra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3599,6 +3609,7 @@ const handleOpenAIExchange = async (authCode: string) => {
|
||||
extra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3628,6 +3639,7 @@ const handleOpenAIExchange = async (authCode: string) => {
|
||||
extra: soraExtra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3705,6 +3717,7 @@ const handleOpenAIValidateRT = async (refreshTokenInput: string) => {
|
||||
extra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3732,6 +3745,7 @@ const handleOpenAIValidateRT = async (refreshTokenInput: string) => {
|
||||
extra: soraExtra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3820,6 +3834,7 @@ const handleSoraValidateST = async (sessionTokenInput: string) => {
|
||||
extra: soraExtra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -3908,6 +3923,7 @@ const handleAntigravityValidateRT = async (refreshTokenInput: string) => {
|
||||
extra: {},
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
@@ -4066,8 +4082,11 @@ const handleAnthropicExchange = async (authCode: string) => {
|
||||
}
|
||||
|
||||
// Add RPM limit settings
|
||||
if (rpmLimitEnabled.value && baseRpm.value != null && baseRpm.value > 0) {
|
||||
extra.base_rpm = baseRpm.value
|
||||
if (rpmLimitEnabled.value) {
|
||||
const DEFAULT_BASE_RPM = 15
|
||||
extra.base_rpm = (baseRpm.value != null && baseRpm.value > 0)
|
||||
? baseRpm.value
|
||||
: DEFAULT_BASE_RPM
|
||||
extra.rpm_strategy = rpmStrategy.value
|
||||
if (rpmStickyBuffer.value != null && rpmStickyBuffer.value > 0) {
|
||||
extra.rpm_sticky_buffer = rpmStickyBuffer.value
|
||||
@@ -4178,8 +4197,11 @@ const handleCookieAuth = async (sessionKey: string) => {
|
||||
}
|
||||
|
||||
// Add RPM limit settings
|
||||
if (rpmLimitEnabled.value && baseRpm.value != null && baseRpm.value > 0) {
|
||||
extra.base_rpm = baseRpm.value
|
||||
if (rpmLimitEnabled.value) {
|
||||
const DEFAULT_BASE_RPM = 15
|
||||
extra.base_rpm = (baseRpm.value != null && baseRpm.value > 0)
|
||||
? baseRpm.value
|
||||
: DEFAULT_BASE_RPM
|
||||
extra.rpm_strategy = rpmStrategy.value
|
||||
if (rpmStickyBuffer.value != null && rpmStickyBuffer.value > 0) {
|
||||
extra.rpm_sticky_buffer = rpmStickyBuffer.value
|
||||
@@ -4225,6 +4247,7 @@ const handleCookieAuth = async (sessionKey: string) => {
|
||||
extra,
|
||||
proxy_id: form.proxy_id,
|
||||
concurrency: form.concurrency,
|
||||
load_factor: form.load_factor || undefined,
|
||||
priority: form.priority,
|
||||
rate_multiplier: form.rate_multiplier,
|
||||
group_ids: form.group_ids,
|
||||
|
||||
@@ -650,11 +650,17 @@
|
||||
<ProxySelector v-model="form.proxy_id" :proxies="proxies" />
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 lg:grid-cols-3">
|
||||
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.concurrency') }}</label>
|
||||
<input v-model.number="form.concurrency" type="number" min="1" class="input" />
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.loadFactor') }}</label>
|
||||
<input v-model.number="form.load_factor" type="number" min="1"
|
||||
class="input" :placeholder="String(form.concurrency || 1)" />
|
||||
<p class="input-hint">{{ t('admin.accounts.loadFactorHint') }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="input-label">{{ t('admin.accounts.priority') }}</label>
|
||||
<input
|
||||
@@ -1465,6 +1471,7 @@ const form = reactive({
|
||||
notes: '',
|
||||
proxy_id: null as number | null,
|
||||
concurrency: 1,
|
||||
load_factor: null as number | null,
|
||||
priority: 1,
|
||||
rate_multiplier: 1,
|
||||
status: 'active' as 'active' | 'inactive',
|
||||
@@ -1498,6 +1505,7 @@ watch(
|
||||
form.notes = newAccount.notes || ''
|
||||
form.proxy_id = newAccount.proxy_id
|
||||
form.concurrency = newAccount.concurrency
|
||||
form.load_factor = newAccount.load_factor ?? null
|
||||
form.priority = newAccount.priority
|
||||
form.rate_multiplier = newAccount.rate_multiplier ?? 1
|
||||
form.status = newAccount.status as 'active' | 'inactive'
|
||||
@@ -2057,6 +2065,10 @@ const handleSubmit = async () => {
|
||||
if (form.expires_at === null) {
|
||||
updatePayload.expires_at = 0
|
||||
}
|
||||
// load_factor: 空值/0/NaN 时发送 0(后端约定 0 = 清除)
|
||||
if (!form.load_factor || form.load_factor <= 0) {
|
||||
updatePayload.load_factor = 0
|
||||
}
|
||||
updatePayload.auto_pause_on_expired = autoPauseOnExpired.value
|
||||
|
||||
// For apikey type, handle credentials update
|
||||
@@ -2196,8 +2208,11 @@ const handleSubmit = async () => {
|
||||
}
|
||||
|
||||
// RPM limit settings
|
||||
if (rpmLimitEnabled.value && baseRpm.value != null && baseRpm.value > 0) {
|
||||
newExtra.base_rpm = baseRpm.value
|
||||
if (rpmLimitEnabled.value) {
|
||||
const DEFAULT_BASE_RPM = 15
|
||||
newExtra.base_rpm = (baseRpm.value != null && baseRpm.value > 0)
|
||||
? baseRpm.value
|
||||
: DEFAULT_BASE_RPM
|
||||
newExtra.rpm_strategy = rpmStrategy.value
|
||||
if (rpmStickyBuffer.value != null && rpmStickyBuffer.value > 0) {
|
||||
newExtra.rpm_sticky_buffer = rpmStickyBuffer.value
|
||||
|
||||
@@ -1939,10 +1939,12 @@ export default {
|
||||
proxy: 'Proxy',
|
||||
noProxy: 'No Proxy',
|
||||
concurrency: 'Concurrency',
|
||||
loadFactor: 'Load Factor',
|
||||
loadFactorHint: 'Defaults to concurrency',
|
||||
priority: 'Priority',
|
||||
priorityHint: 'Lower value accounts are used first',
|
||||
billingRateMultiplier: 'Billing Rate Multiplier',
|
||||
billingRateMultiplierHint: '>=0, 0 means free. Affects account billing only',
|
||||
billingRateMultiplierHint: '0 = free, affects account billing only',
|
||||
expiresAt: 'Expires At',
|
||||
expiresAtHint: 'Leave empty for no expiration',
|
||||
higherPriorityFirst: 'Lower value means higher priority',
|
||||
|
||||
@@ -2073,10 +2073,12 @@ export default {
|
||||
proxy: '代理',
|
||||
noProxy: '无代理',
|
||||
concurrency: '并发数',
|
||||
loadFactor: '负载因子',
|
||||
loadFactorHint: '不填则等于并发数',
|
||||
priority: '优先级',
|
||||
priorityHint: '优先级越小的账号优先使用',
|
||||
billingRateMultiplier: '账号计费倍率',
|
||||
billingRateMultiplierHint: '>=0,0 表示该账号计费为 0;仅影响账号计费口径',
|
||||
billingRateMultiplierHint: '0 表示不计费,仅影响账号计费',
|
||||
expiresAt: '过期时间',
|
||||
expiresAtHint: '留空表示不过期',
|
||||
higherPriorityFirst: '数值越小优先级越高',
|
||||
|
||||
@@ -657,6 +657,7 @@ export interface Account {
|
||||
} & Record<string, unknown>)
|
||||
proxy_id: number | null
|
||||
concurrency: number
|
||||
load_factor?: number | null
|
||||
current_concurrency?: number // Real-time concurrency count from Redis
|
||||
priority: number
|
||||
rate_multiplier?: number // Account billing multiplier (>=0, 0 means free)
|
||||
@@ -791,6 +792,7 @@ export interface CreateAccountRequest {
|
||||
extra?: Record<string, unknown>
|
||||
proxy_id?: number | null
|
||||
concurrency?: number
|
||||
load_factor?: number | null
|
||||
priority?: number
|
||||
rate_multiplier?: number // Account billing multiplier (>=0, 0 means free)
|
||||
group_ids?: number[]
|
||||
@@ -807,6 +809,7 @@ export interface UpdateAccountRequest {
|
||||
extra?: Record<string, unknown>
|
||||
proxy_id?: number | null
|
||||
concurrency?: number
|
||||
load_factor?: number | null
|
||||
priority?: number
|
||||
rate_multiplier?: number // Account billing multiplier (>=0, 0 means free)
|
||||
schedulable?: boolean
|
||||
|
||||
Reference in New Issue
Block a user