Commits on Source 11

  • Elliot Forbes's avatar
    test(featureflag): add comprehensive panic and race condition tests · bbe4dfa3
    Elliot Forbes authored
    Add panic_test.go and race_condition_test.go to detect nil pointer dereferences
    and panics in concurrent evaluation scenarios, particularly during provider
    lifecycle transitions. Tests use atomic counters and panic recovery to safely
    detect panics in concurrent goroutines.
    
    Document the identified race condition between concurrent evaluations and
    provider shutdown in RACE_CONDITION_NOTES.md with root cause analysis and
    four potential solutions (graceful draining recommended).
    
    Key test scenarios covered:
    - Concurrent flag evaluations without panics
    - Shutdown during in-flight evaluations
    - Rapid provider replacement under load
    - Multiple client instances racing on shutdown
    - Cache layer under concurrent access
    - Context cancellation edge cases
    
    Tests properly ignore evaluation errors (FLAG_NOT_FOUND from empty provider)
    and focus on detecting panics via defer + recover() in goroutines.
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    bbe4dfa3
  • Elliot Forbes's avatar
  • Elliot Forbes's avatar
    fix(featureflag): prevent race condition during concurrent evaluations and shutdown · 6a393963
    Elliot Forbes authored
    Add RWMutex-based graceful draining to prevent nil pointer dereference when
    evaluations are in-flight during provider shutdown.
    
    The race condition occurred because:
    1. Evaluation acquires reference to provider
    2. Shutdown concurrently replaces provider with NoopProvider
    3. In-flight evaluation tries to use stale provider reference
    4. Provider's HTTP transport encounters nil pointer
    
    Solution: Protect evaluations with read lock (RLock), and acquire write lock
    in Shutdown to block new evaluations and wait for in-flight ones to complete
    before replacing the provider.
    
    This ensures that SetNamedProviderAndWait never races with active evaluations,
    making the panic impossible to trigger in normal operation.
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    6a393963
  • Elliot Forbes's avatar
    chore: remove race condition notes documentation · 9edeb7f9
    Elliot Forbes authored
    The notes file is helpful for analysis but not necessary for the MR.
    Focus should be on the test coverage and the fix itself.
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    9edeb7f9
  • Elliot Forbes's avatar
    refactor(featureflag): add panic recovery to evaluation methods · 598afe21
    Elliot Forbes authored
    Convert panics in the evaluation chain to well-defined errors instead of
    propagating them to the caller. This adds an extra layer of defensive
    programming to ensure that any panic in the OpenFeature SDK or provider
    implementations is caught and returned as an error with the default value.
    
    Changes:
    - Add panic recovery decorator using defer + recover() in BooleanValueDetails
    - Add panic recovery decorator using defer + recover() in StringValueDetails
    - Return default value and descriptive error message on panic
    - Use named return values to allow defer to set error state
    
    Impact:
    - Evaluation panics become safe, predictable errors
    - Callers get graceful error handling instead of crashes
    - Combined with graceful draining, makes the client panic-proof
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    598afe21
  • Elliot Forbes's avatar
    refactor(featureflag): reduce duplication with generic evaluate helper · 7615580d
    Elliot Forbes authored
    Extract common evaluation pattern (mutex locking, panic recovery, tracing)
    into a generic `evaluate` function to eliminate boilerplate duplication
    between BooleanValueDetails and StringValueDetails.
    
    Changes:
    - Add generic evaluate[T] helper function using Go 1.18+ generics
    - Move all mutex, panic recovery, and tracer logic to evaluate()
    - Reduce BooleanValueDetails to simple delegation + error wrapping
    - Reduce StringValueDetails to simple delegation + error wrapping
    
    Benefits:
    - Single source of truth for synchronization and panic recovery
    - Reduced code duplication (~30 lines eliminated)
    - Easier to maintain and extend with new evaluation types
    - Same behavior, improved readability
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    7615580d
  • Elliot Forbes's avatar
    fix: extract value from details for recordSpan · 39cb8ed6
    Elliot Forbes authored
    The recordSpan call needs the actual value (bool/string), not the
    entire evaluation details object. Add type assertion to extract
    the value correctly from the generic result.
    39cb8ed6
  • Elliot Forbes's avatar
    fix(featureflag): address review feedback · ce22924f
    Elliot Forbes authored
    - Use named return values for panic recovery in evaluate() function
    - Remove unused EvaluationDetails return from evaluate()
    - Replace t.Logf assertions with assert.Error() in tests
    - Replace rune casting with strconv.Itoa() for cleaner code
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    ce22924f
  • Elliot Forbes's avatar
    fix: address linting issues and update nil client test · c1eecb28
    Elliot Forbes authored
    - Remove redundant empty defer block in tracer operations
    - Add nolint:errcheck comments for intentional recover() no-ops
    - Update TestPanicOnNilClient to expect error instead of panic (better UX)
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    c1eecb28
  • Elliot Forbes's avatar
    refactor(featureflag): simplify evaluate to single recovery defer · 82735765
    Elliot Forbes authored
    Address review feedback on evaluate() complexity:
    - Reduce from 3 recover statements + 5 defers to 1 recover + 2 defers
    - Simplify closure signature: returns (T, error) instead of adding EvaluationDetails
    - Use plain defer span.End() - outer recover catches any span panics
    - Extract value/details from result via helper when recording span
    
    The original bug was a race condition solved by the RWMutex; the extra
    defensive layers added unnecessary cognitive load without improving safety.
    
    Co-Authored-By: default avatarClaude Haiku 4.5 <noreply@anthropic.com>
    82735765
  • Luke Hollinda's avatar
    Merge branch 'ef-ensure-feature-flag-client-cant-panic' into 'master' · 63cda97a
    Luke Hollinda authored
    Fix featureflag race condition during concurrent evaluations and shutdown
    
    See merge request gitlab-org/labkit!442
    
    Merged-by: default avatarLuke Hollinda <lhollinda@gitlab.com>
    Approved-by: default avatarLuke Hollinda <lhollinda@gitlab.com>
    Co-authored-by: Elliot Forbes's avatare_forbes <eforbes@gitlab.com>
    63cda97a
Loading
Loading