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

@@ -389,6 +389,27 @@ func (_u *UserUpdate) AddTotalRecharged(v float64) *UserUpdate {
return _u
}
// SetRpmLimit sets the "rpm_limit" field.
func (_u *UserUpdate) SetRpmLimit(v int) *UserUpdate {
_u.mutation.ResetRpmLimit()
_u.mutation.SetRpmLimit(v)
return _u
}
// SetNillableRpmLimit sets the "rpm_limit" field if the given value is not nil.
func (_u *UserUpdate) SetNillableRpmLimit(v *int) *UserUpdate {
if v != nil {
_u.SetRpmLimit(*v)
}
return _u
}
// AddRpmLimit adds value to the "rpm_limit" field.
func (_u *UserUpdate) AddRpmLimit(v int) *UserUpdate {
_u.mutation.AddRpmLimit(v)
return _u
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *UserUpdate) AddAPIKeyIDs(ids ...int64) *UserUpdate {
_u.mutation.AddAPIKeyIDs(ids...)
@@ -1008,6 +1029,12 @@ func (_u *UserUpdate) sqlSave(ctx context.Context) (_node int, err error) {
if value, ok := _u.mutation.AddedTotalRecharged(); ok {
_spec.AddField(user.FieldTotalRecharged, field.TypeFloat64, value)
}
if value, ok := _u.mutation.RpmLimit(); ok {
_spec.SetField(user.FieldRpmLimit, field.TypeInt, value)
}
if value, ok := _u.mutation.AddedRpmLimit(); ok {
_spec.AddField(user.FieldRpmLimit, field.TypeInt, value)
}
if _u.mutation.APIKeysCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,
@@ -1930,6 +1957,27 @@ func (_u *UserUpdateOne) AddTotalRecharged(v float64) *UserUpdateOne {
return _u
}
// SetRpmLimit sets the "rpm_limit" field.
func (_u *UserUpdateOne) SetRpmLimit(v int) *UserUpdateOne {
_u.mutation.ResetRpmLimit()
_u.mutation.SetRpmLimit(v)
return _u
}
// SetNillableRpmLimit sets the "rpm_limit" field if the given value is not nil.
func (_u *UserUpdateOne) SetNillableRpmLimit(v *int) *UserUpdateOne {
if v != nil {
_u.SetRpmLimit(*v)
}
return _u
}
// AddRpmLimit adds value to the "rpm_limit" field.
func (_u *UserUpdateOne) AddRpmLimit(v int) *UserUpdateOne {
_u.mutation.AddRpmLimit(v)
return _u
}
// AddAPIKeyIDs adds the "api_keys" edge to the APIKey entity by IDs.
func (_u *UserUpdateOne) AddAPIKeyIDs(ids ...int64) *UserUpdateOne {
_u.mutation.AddAPIKeyIDs(ids...)
@@ -2579,6 +2627,12 @@ func (_u *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) {
if value, ok := _u.mutation.AddedTotalRecharged(); ok {
_spec.AddField(user.FieldTotalRecharged, field.TypeFloat64, value)
}
if value, ok := _u.mutation.RpmLimit(); ok {
_spec.SetField(user.FieldRpmLimit, field.TypeInt, value)
}
if value, ok := _u.mutation.AddedRpmLimit(); ok {
_spec.AddField(user.FieldRpmLimit, field.TypeInt, value)
}
if _u.mutation.APIKeysCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.O2M,