Fix Codex exhausted snapshot propagation

This commit is contained in:
ius
2026-03-11 15:47:39 +08:00
parent 2694149489
commit 2fc6aaf936
5 changed files with 248 additions and 30 deletions

View File

@@ -1190,6 +1190,9 @@ func (r *accountRepository) UpdateExtra(ctx context.Context, id int64, updates m
if err := enqueueSchedulerOutbox(ctx, r.sql, service.SchedulerOutboxEventAccountChanged, &id, nil, nil); err != nil {
logger.LegacyPrintf("repository.account", "[SchedulerOutbox] enqueue extra update failed: account=%d err=%v", id, err)
}
} else if shouldSyncSchedulerSnapshotForExtraUpdates(updates) {
// codex 限流快照仍需要让调度缓存尽快看见,避免 DB 抖动时丢失自愈链路。
r.syncSchedulerAccountSnapshot(ctx, id)
}
return nil
}
@@ -1207,6 +1210,10 @@ func shouldEnqueueSchedulerOutboxForExtraUpdates(updates map[string]any) bool {
return false
}
func shouldSyncSchedulerSnapshotForExtraUpdates(updates map[string]any) bool {
return codexExtraIndicatesRateLimit(updates, "7d") || codexExtraIndicatesRateLimit(updates, "5h")
}
func isSchedulerNeutralAccountExtraKey(key string) bool {
key = strings.TrimSpace(key)
if key == "" {
@@ -1218,6 +1225,78 @@ func isSchedulerNeutralAccountExtraKey(key string) bool {
return strings.HasPrefix(key, "codex_")
}
func codexExtraIndicatesRateLimit(updates map[string]any, window string) bool {
if len(updates) == 0 {
return false
}
usedValue, ok := updates["codex_"+window+"_used_percent"]
if !ok || !extraValueIndicatesExhausted(usedValue) {
return false
}
return extraValueHasResetMarker(updates["codex_"+window+"_reset_at"]) ||
extraValueHasPositiveNumber(updates["codex_"+window+"_reset_after_seconds"])
}
func extraValueIndicatesExhausted(value any) bool {
number, ok := extraValueToFloat64(value)
return ok && number >= 100-1e-9
}
func extraValueHasPositiveNumber(value any) bool {
number, ok := extraValueToFloat64(value)
return ok && number > 0
}
func extraValueHasResetMarker(value any) bool {
switch v := value.(type) {
case string:
return strings.TrimSpace(v) != ""
case time.Time:
return !v.IsZero()
case *time.Time:
return v != nil && !v.IsZero()
default:
return false
}
}
func extraValueToFloat64(value any) (float64, bool) {
switch v := value.(type) {
case float64:
return v, true
case float32:
return float64(v), true
case int:
return float64(v), true
case int8:
return float64(v), true
case int16:
return float64(v), true
case int32:
return float64(v), true
case int64:
return float64(v), true
case uint:
return float64(v), true
case uint8:
return float64(v), true
case uint16:
return float64(v), true
case uint32:
return float64(v), true
case uint64:
return float64(v), true
case json.Number:
parsed, err := v.Float64()
return parsed, err == nil
case string:
parsed, err := strconv.ParseFloat(strings.TrimSpace(v), 64)
return parsed, err == nil
default:
return 0, false
}
}
func (r *accountRepository) BulkUpdate(ctx context.Context, ids []int64, updates service.AccountBulkUpdate) (int64, error) {
if len(ids) == 0 {
return 0, nil