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:
james-6-23
2026-04-23 03:33:52 +08:00
parent ef967d8f8a
commit dc5d42addc
79 changed files with 2831 additions and 140 deletions

View File

@@ -425,6 +425,20 @@ func (_c *GroupCreate) SetNillableMessagesDispatchModelConfig(v *domain.OpenAIMe
return _c
}
// SetRpmLimit sets the "rpm_limit" field.
func (_c *GroupCreate) SetRpmLimit(v int) *GroupCreate {
_c.mutation.SetRpmLimit(v)
return _c
}
// SetNillableRpmLimit sets the "rpm_limit" field if the given value is not nil.
func (_c *GroupCreate) SetNillableRpmLimit(v *int) *GroupCreate {
if v != nil {
_c.SetRpmLimit(*v)
}
return _c
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_c *GroupCreate) AddAPIKeyIDs(ids ...int64) *GroupCreate {
_c.mutation.AddAPIKeyIDs(ids...)
@@ -630,6 +644,10 @@ func (_c *GroupCreate) defaults() error {
v := group.DefaultMessagesDispatchModelConfig
_c.mutation.SetMessagesDispatchModelConfig(v)
}
if _, ok := _c.mutation.RpmLimit(); !ok {
v := group.DefaultRpmLimit
_c.mutation.SetRpmLimit(v)
}
return nil
}
@@ -717,6 +735,9 @@ func (_c *GroupCreate) check() error {
if _, ok := _c.mutation.MessagesDispatchModelConfig(); !ok {
return &ValidationError{Name: "messages_dispatch_model_config", err: errors.New(`ent: missing required field "Group.messages_dispatch_model_config"`)}
}
if _, ok := _c.mutation.RpmLimit(); !ok {
return &ValidationError{Name: "rpm_limit", err: errors.New(`ent: missing required field "Group.rpm_limit"`)}
}
return nil
}
@@ -864,6 +885,10 @@ func (_c *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) {
_spec.SetField(group.FieldMessagesDispatchModelConfig, field.TypeJSON, value)
_node.MessagesDispatchModelConfig = value
}
if value, ok := _c.mutation.RpmLimit(); ok {
_spec.SetField(group.FieldRpmLimit, field.TypeInt, value)
_node.RpmLimit = value
}
if nodes := _c.mutation.APIKeysIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
@@ -1500,6 +1525,24 @@ func (u *GroupUpsert) UpdateMessagesDispatchModelConfig() *GroupUpsert {
return u
}
// SetRpmLimit sets the "rpm_limit" field.
func (u *GroupUpsert) SetRpmLimit(v int) *GroupUpsert {
u.Set(group.FieldRpmLimit, v)
return u
}
// UpdateRpmLimit sets the "rpm_limit" field to the value that was provided on create.
func (u *GroupUpsert) UpdateRpmLimit() *GroupUpsert {
u.SetExcluded(group.FieldRpmLimit)
return u
}
// AddRpmLimit adds v to the "rpm_limit" field.
func (u *GroupUpsert) AddRpmLimit(v int) *GroupUpsert {
u.Add(group.FieldRpmLimit, v)
return u
}
// UpdateNewValues updates the mutable fields using the new values that were set on create.
// Using this option is equivalent to using:
//
@@ -2105,6 +2148,27 @@ func (u *GroupUpsertOne) UpdateMessagesDispatchModelConfig() *GroupUpsertOne {
})
}
// SetRpmLimit sets the "rpm_limit" field.
func (u *GroupUpsertOne) SetRpmLimit(v int) *GroupUpsertOne {
return u.Update(func(s *GroupUpsert) {
s.SetRpmLimit(v)
})
}
// AddRpmLimit adds v to the "rpm_limit" field.
func (u *GroupUpsertOne) AddRpmLimit(v int) *GroupUpsertOne {
return u.Update(func(s *GroupUpsert) {
s.AddRpmLimit(v)
})
}
// UpdateRpmLimit sets the "rpm_limit" field to the value that was provided on create.
func (u *GroupUpsertOne) UpdateRpmLimit() *GroupUpsertOne {
return u.Update(func(s *GroupUpsert) {
s.UpdateRpmLimit()
})
}
// Exec executes the query.
func (u *GroupUpsertOne) Exec(ctx context.Context) error {
if len(u.create.conflict) == 0 {
@@ -2876,6 +2940,27 @@ func (u *GroupUpsertBulk) UpdateMessagesDispatchModelConfig() *GroupUpsertBulk {
})
}
// SetRpmLimit sets the "rpm_limit" field.
func (u *GroupUpsertBulk) SetRpmLimit(v int) *GroupUpsertBulk {
return u.Update(func(s *GroupUpsert) {
s.SetRpmLimit(v)
})
}
// AddRpmLimit adds v to the "rpm_limit" field.
func (u *GroupUpsertBulk) AddRpmLimit(v int) *GroupUpsertBulk {
return u.Update(func(s *GroupUpsert) {
s.AddRpmLimit(v)
})
}
// UpdateRpmLimit sets the "rpm_limit" field to the value that was provided on create.
func (u *GroupUpsertBulk) UpdateRpmLimit() *GroupUpsertBulk {
return u.Update(func(s *GroupUpsert) {
s.UpdateRpmLimit()
})
}
// Exec executes the query.
func (u *GroupUpsertBulk) Exec(ctx context.Context) error {
if u.create.err != nil {