Skip to content

Commit fe25e46

Browse files
committed
fix(auth): persist runtime scheduler state across restarts
1 parent ed226de commit fe25e46

File tree

6 files changed

+1265
-12
lines changed

6 files changed

+1265
-12
lines changed

sdk/cliproxy/auth/conductor.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,11 +1117,7 @@ func (m *Manager) Update(ctx context.Context, auth *Auth) (*Auth, error) {
11171117
auth.Index = existing.Index
11181118
auth.indexAssigned = existing.indexAssigned
11191119
}
1120-
if !existing.Disabled && existing.Status != StatusDisabled && !auth.Disabled && auth.Status != StatusDisabled {
1121-
if len(auth.ModelStates) == 0 && len(existing.ModelStates) > 0 {
1122-
auth.ModelStates = existing.ModelStates
1123-
}
1124-
}
1120+
preserveRuntimeSnapshotState(auth, existing, time.Now())
11251121
}
11261122
auth.EnsureIndex()
11271123
authClone := auth.Clone()

sdk/cliproxy/auth/conductor_update_test.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@ package auth
33
import (
44
"context"
55
"testing"
6+
"time"
67
)
78

89
func TestManager_Update_PreservesModelStates(t *testing.T) {
910
m := NewManager(nil, nil, nil)
1011

1112
model := "test-model"
1213
backoffLevel := 7
14+
now := time.Date(2026, time.April, 18, 12, 0, 0, 0, time.UTC)
15+
nextRetryAfter := now.Add(10 * time.Minute)
16+
nextRecoverAt := now.Add(20 * time.Minute)
1317

1418
if _, errRegister := m.Register(context.Background(), &Auth{
1519
ID: "auth-1",
1620
Provider: "claude",
1721
Metadata: map[string]any{"k": "v"},
1822
ModelStates: map[string]*ModelState{
1923
model: {
20-
Quota: QuotaState{BackoffLevel: backoffLevel},
24+
Status: StatusError,
25+
StatusMessage: "cooldown",
26+
Unavailable: true,
27+
NextRetryAfter: nextRetryAfter,
28+
LastError: &Error{Code: "rate_limit", Message: "retry later", Retryable: true, HTTPStatus: 429},
29+
Quota: QuotaState{Exceeded: true, Reason: "quota", NextRecoverAt: nextRecoverAt, BackoffLevel: backoffLevel},
30+
UpdatedAt: now,
2131
},
2232
},
2333
}); errRegister != nil {
@@ -163,6 +173,9 @@ func TestManager_Update_ActiveInheritsModelStates(t *testing.T) {
163173

164174
model := "active-model"
165175
backoffLevel := 3
176+
now := time.Date(2026, time.April, 18, 12, 0, 0, 0, time.UTC)
177+
nextRetryAfter := now.Add(5 * time.Minute)
178+
nextRecoverAt := now.Add(15 * time.Minute)
166179

167180
// Register an active auth with ModelStates.
168181
if _, err := m.Register(context.Background(), &Auth{
@@ -171,7 +184,13 @@ func TestManager_Update_ActiveInheritsModelStates(t *testing.T) {
171184
Status: StatusActive,
172185
ModelStates: map[string]*ModelState{
173186
model: {
174-
Quota: QuotaState{BackoffLevel: backoffLevel},
187+
Status: StatusError,
188+
StatusMessage: "cooldown",
189+
Unavailable: true,
190+
NextRetryAfter: nextRetryAfter,
191+
LastError: &Error{Code: "model_rate_limit", Message: "busy", Retryable: true, HTTPStatus: 429},
192+
Quota: QuotaState{Exceeded: true, Reason: "quota", NextRecoverAt: nextRecoverAt, BackoffLevel: backoffLevel},
193+
UpdatedAt: now,
175194
},
176195
},
177196
}); err != nil {

0 commit comments

Comments
 (0)