Skip to content

Commit e911eaa

Browse files
committed
chore(reliability): recover() in fire-and-forget goroutines (closes #672)
Add deferred recover() to the three unprotected background goroutines surfaced in the #669/#670 sibling audit: - internal/auth/service_apikeys.go: UpdateLastUsed async goroutine - internal/api/db_rate_limiter.go: cleanup async goroutine - internal/api/handler_accounts.go: GCP ts.Token() goroutine; panic now also sends an error back on tokenChan so the caller returns promptly rather than blocking until the 15s deadline fires Matches the existing pattern in ri_utilization_cache.go and scheduler.go.
1 parent 1d9f1b8 commit e911eaa

3 files changed

Lines changed: 16 additions & 0 deletions

File tree

‎internal/api/db_rate_limiter.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ func (rl *DBRateLimiter) maybeCleanup() {
169169
// Run cleanup in background
170170
go func() {
171171
defer rl.cleanupRunning.Store(false)
172+
defer func() {
173+
if r := recover(); r != nil {
174+
logging.Warnf("db_rate_limiter: cleanup goroutine panic: %v", r)
175+
}
176+
}()
172177
rl.cleanup()
173178
}()
174179
}

‎internal/api/handler_accounts.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,12 @@ func gcpTokenExchangeAttempt(ctx context.Context, ts oauth2.TokenSource) (Accoun
881881
defer cancel()
882882
tokenChan := make(chan tokenResult, 1)
883883
go func() {
884+
defer func() {
885+
if r := recover(); r != nil {
886+
logging.Warnf("handler_accounts: gcp token-exchange goroutine panic: %v", r)
887+
tokenChan <- tokenResult{err: fmt.Errorf("token exchange panic: %v", r)}
888+
}
889+
}()
884890
tok, err := ts.Token()
885891
tokenChan <- tokenResult{tok: tok, err: err}
886892
}()

‎internal/auth/service_apikeys.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,11 @@ func (s *Service) ValidateUserAPIKey(ctx context.Context, apiKey string) (*UserA
291291
keyID := key.ID
292292
go func() {
293293
if _, sfErr, _ := s.lastUsedSFG.Do(keyID, func() (any, error) {
294+
defer func() {
295+
if r := recover(); r != nil {
296+
logging.Warnf("service_apikeys: UpdateLastUsed goroutine panic: %v", r)
297+
}
298+
}()
294299
updateCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
295300
defer cancel()
296301
if err := s.UpdateLastUsed(updateCtx, keyID); err != nil {

0 commit comments

Comments
 (0)