feat(rpm): RPM 限流模块优化
P0: - rpm_override 嵌入 Auth Cache Snapshot,消除每请求 DB 查询 (snapshot v6→v7) - 429 RPM 响应返回 Retry-After 头(当前分钟剩余秒数) P1: - ClearAll 按钮直连 DELETE API,带 loading 防重复 - 新增 GET /admin/users/:id/rpm-status 管理员 RPM 用量查询端点 优化: - checkRPM 从级联互斥改为并行取最严,user.rpm_limit 作为全局硬上限始终生效 - Override/Group 变更后自动失效 auth cache - fail-open 语义不变,Redis 故障不阻塞业务
This commit is contained in:
@@ -10102,6 +10102,8 @@ type GroupMutation struct {
|
||||
require_privacy_set *bool
|
||||
default_mapped_model *string
|
||||
messages_dispatch_model_config *domain.OpenAIMessagesDispatchModelConfig
|
||||
rpm_limit *int
|
||||
addrpm_limit *int
|
||||
clearedFields map[string]struct{}
|
||||
api_keys map[int64]struct{}
|
||||
removedapi_keys map[int64]struct{}
|
||||
@@ -11690,6 +11692,62 @@ func (m *GroupMutation) ResetMessagesDispatchModelConfig() {
|
||||
m.messages_dispatch_model_config = nil
|
||||
}
|
||||
|
||||
// SetRpmLimit sets the "rpm_limit" field.
|
||||
func (m *GroupMutation) SetRpmLimit(i int) {
|
||||
m.rpm_limit = &i
|
||||
m.addrpm_limit = nil
|
||||
}
|
||||
|
||||
// RpmLimit returns the value of the "rpm_limit" field in the mutation.
|
||||
func (m *GroupMutation) RpmLimit() (r int, exists bool) {
|
||||
v := m.rpm_limit
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldRpmLimit returns the old "rpm_limit" field's value of the Group entity.
|
||||
// If the Group 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 *GroupMutation) OldRpmLimit(ctx context.Context) (v int, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldRpmLimit is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldRpmLimit requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldRpmLimit: %w", err)
|
||||
}
|
||||
return oldValue.RpmLimit, nil
|
||||
}
|
||||
|
||||
// AddRpmLimit adds i to the "rpm_limit" field.
|
||||
func (m *GroupMutation) AddRpmLimit(i int) {
|
||||
if m.addrpm_limit != nil {
|
||||
*m.addrpm_limit += i
|
||||
} else {
|
||||
m.addrpm_limit = &i
|
||||
}
|
||||
}
|
||||
|
||||
// AddedRpmLimit returns the value that was added to the "rpm_limit" field in this mutation.
|
||||
func (m *GroupMutation) AddedRpmLimit() (r int, exists bool) {
|
||||
v := m.addrpm_limit
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ResetRpmLimit resets all changes to the "rpm_limit" field.
|
||||
func (m *GroupMutation) ResetRpmLimit() {
|
||||
m.rpm_limit = nil
|
||||
m.addrpm_limit = nil
|
||||
}
|
||||
|
||||
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by ids.
|
||||
func (m *GroupMutation) AddAPIKeyIDs(ids ...int64) {
|
||||
if m.api_keys == nil {
|
||||
@@ -12048,7 +12106,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)
|
||||
}
|
||||
@@ -12139,6 +12197,9 @@ func (m *GroupMutation) Fields() []string {
|
||||
if m.messages_dispatch_model_config != nil {
|
||||
fields = append(fields, group.FieldMessagesDispatchModelConfig)
|
||||
}
|
||||
if m.rpm_limit != nil {
|
||||
fields = append(fields, group.FieldRpmLimit)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -12207,6 +12268,8 @@ func (m *GroupMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.DefaultMappedModel()
|
||||
case group.FieldMessagesDispatchModelConfig:
|
||||
return m.MessagesDispatchModelConfig()
|
||||
case group.FieldRpmLimit:
|
||||
return m.RpmLimit()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -12276,6 +12339,8 @@ func (m *GroupMutation) OldField(ctx context.Context, name string) (ent.Value, e
|
||||
return m.OldDefaultMappedModel(ctx)
|
||||
case group.FieldMessagesDispatchModelConfig:
|
||||
return m.OldMessagesDispatchModelConfig(ctx)
|
||||
case group.FieldRpmLimit:
|
||||
return m.OldRpmLimit(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown Group field %s", name)
|
||||
}
|
||||
@@ -12495,6 +12560,13 @@ func (m *GroupMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetMessagesDispatchModelConfig(v)
|
||||
return nil
|
||||
case group.FieldRpmLimit:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetRpmLimit(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group field %s", name)
|
||||
}
|
||||
@@ -12536,6 +12608,9 @@ func (m *GroupMutation) AddedFields() []string {
|
||||
if m.addsort_order != nil {
|
||||
fields = append(fields, group.FieldSortOrder)
|
||||
}
|
||||
if m.addrpm_limit != nil {
|
||||
fields = append(fields, group.FieldRpmLimit)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -12566,6 +12641,8 @@ func (m *GroupMutation) AddedField(name string) (ent.Value, bool) {
|
||||
return m.AddedFallbackGroupIDOnInvalidRequest()
|
||||
case group.FieldSortOrder:
|
||||
return m.AddedSortOrder()
|
||||
case group.FieldRpmLimit:
|
||||
return m.AddedRpmLimit()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -12652,6 +12729,13 @@ func (m *GroupMutation) AddField(name string, value ent.Value) error {
|
||||
}
|
||||
m.AddSortOrder(v)
|
||||
return nil
|
||||
case group.FieldRpmLimit:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddRpmLimit(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group numeric field %s", name)
|
||||
}
|
||||
@@ -12838,6 +12922,9 @@ func (m *GroupMutation) ResetField(name string) error {
|
||||
case group.FieldMessagesDispatchModelConfig:
|
||||
m.ResetMessagesDispatchModelConfig()
|
||||
return nil
|
||||
case group.FieldRpmLimit:
|
||||
m.ResetRpmLimit()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Group field %s", name)
|
||||
}
|
||||
@@ -32681,6 +32768,8 @@ type UserMutation struct {
|
||||
balance_notify_extra_emails *string
|
||||
total_recharged *float64
|
||||
addtotal_recharged *float64
|
||||
rpm_limit *int
|
||||
addrpm_limit *int
|
||||
clearedFields map[string]struct{}
|
||||
api_keys map[int64]struct{}
|
||||
removedapi_keys map[int64]struct{}
|
||||
@@ -33772,6 +33861,62 @@ func (m *UserMutation) ResetTotalRecharged() {
|
||||
m.addtotal_recharged = nil
|
||||
}
|
||||
|
||||
// SetRpmLimit sets the "rpm_limit" field.
|
||||
func (m *UserMutation) SetRpmLimit(i int) {
|
||||
m.rpm_limit = &i
|
||||
m.addrpm_limit = nil
|
||||
}
|
||||
|
||||
// RpmLimit returns the value of the "rpm_limit" field in the mutation.
|
||||
func (m *UserMutation) RpmLimit() (r int, exists bool) {
|
||||
v := m.rpm_limit
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldRpmLimit returns the old "rpm_limit" field's value of the User entity.
|
||||
// If the User 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 *UserMutation) OldRpmLimit(ctx context.Context) (v int, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldRpmLimit is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldRpmLimit requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldRpmLimit: %w", err)
|
||||
}
|
||||
return oldValue.RpmLimit, nil
|
||||
}
|
||||
|
||||
// AddRpmLimit adds i to the "rpm_limit" field.
|
||||
func (m *UserMutation) AddRpmLimit(i int) {
|
||||
if m.addrpm_limit != nil {
|
||||
*m.addrpm_limit += i
|
||||
} else {
|
||||
m.addrpm_limit = &i
|
||||
}
|
||||
}
|
||||
|
||||
// AddedRpmLimit returns the value that was added to the "rpm_limit" field in this mutation.
|
||||
func (m *UserMutation) AddedRpmLimit() (r int, exists bool) {
|
||||
v := m.addrpm_limit
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// ResetRpmLimit resets all changes to the "rpm_limit" field.
|
||||
func (m *UserMutation) ResetRpmLimit() {
|
||||
m.rpm_limit = nil
|
||||
m.addrpm_limit = nil
|
||||
}
|
||||
|
||||
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by ids.
|
||||
func (m *UserMutation) AddAPIKeyIDs(ids ...int64) {
|
||||
if m.api_keys == nil {
|
||||
@@ -34454,7 +34599,7 @@ func (m *UserMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *UserMutation) Fields() []string {
|
||||
fields := make([]string, 0, 22)
|
||||
fields := make([]string, 0, 23)
|
||||
if m.created_at != nil {
|
||||
fields = append(fields, user.FieldCreatedAt)
|
||||
}
|
||||
@@ -34521,6 +34666,9 @@ func (m *UserMutation) Fields() []string {
|
||||
if m.total_recharged != nil {
|
||||
fields = append(fields, user.FieldTotalRecharged)
|
||||
}
|
||||
if m.rpm_limit != nil {
|
||||
fields = append(fields, user.FieldRpmLimit)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -34573,6 +34721,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.BalanceNotifyExtraEmails()
|
||||
case user.FieldTotalRecharged:
|
||||
return m.TotalRecharged()
|
||||
case user.FieldRpmLimit:
|
||||
return m.RpmLimit()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -34626,6 +34776,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er
|
||||
return m.OldBalanceNotifyExtraEmails(ctx)
|
||||
case user.FieldTotalRecharged:
|
||||
return m.OldTotalRecharged(ctx)
|
||||
case user.FieldRpmLimit:
|
||||
return m.OldRpmLimit(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown User field %s", name)
|
||||
}
|
||||
@@ -34789,6 +34941,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetTotalRecharged(v)
|
||||
return nil
|
||||
case user.FieldRpmLimit:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetRpmLimit(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User field %s", name)
|
||||
}
|
||||
@@ -34809,6 +34968,9 @@ func (m *UserMutation) AddedFields() []string {
|
||||
if m.addtotal_recharged != nil {
|
||||
fields = append(fields, user.FieldTotalRecharged)
|
||||
}
|
||||
if m.addrpm_limit != nil {
|
||||
fields = append(fields, user.FieldRpmLimit)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -34825,6 +34987,8 @@ func (m *UserMutation) AddedField(name string) (ent.Value, bool) {
|
||||
return m.AddedBalanceNotifyThreshold()
|
||||
case user.FieldTotalRecharged:
|
||||
return m.AddedTotalRecharged()
|
||||
case user.FieldRpmLimit:
|
||||
return m.AddedRpmLimit()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -34862,6 +35026,13 @@ func (m *UserMutation) AddField(name string, value ent.Value) error {
|
||||
}
|
||||
m.AddTotalRecharged(v)
|
||||
return nil
|
||||
case user.FieldRpmLimit:
|
||||
v, ok := value.(int)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.AddRpmLimit(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User numeric field %s", name)
|
||||
}
|
||||
@@ -34994,6 +35165,9 @@ func (m *UserMutation) ResetField(name string) error {
|
||||
case user.FieldTotalRecharged:
|
||||
m.ResetTotalRecharged()
|
||||
return nil
|
||||
case user.FieldRpmLimit:
|
||||
m.ResetRpmLimit()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown User field %s", name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user