Class: Stoplight::Infrastructure::Memory::Storage::WindowMetrics

Inherits:
Object
  • Object
show all
Defined in:
lib/stoplight/infrastructure/memory/storage/window_metrics.rb

Overview

Note:

All public methods are synchronized via mutex to ensure thread safety.

Thread-safe in-memory storage for time-windowed light @

This class tracks success and failure counts within a sliding time window, along with consecutive counters and the most recent error. It’s designed for single-process deployments where distributed coordination isn’t needed.

The sliding window approach provides more accurate error rate calculations than consecutive-error counting, as it considers the full picture of recent traffic rather than just the most recent streak.

Instance Method Summary collapse

Constructor Details

#initialize(window_size:, clock:) ⇒ WindowMetrics

Returns a new instance of WindowMetrics.



20
21
22
23
24
25
26
# File 'lib/stoplight/infrastructure/memory/storage/window_metrics.rb', line 20

def initialize(window_size:, clock:)
  @clock = clock
  @mutex = Mutex.new
  @window_size = window_size

  initialize_metrics
end

Instance Method Details

#clearObject



78
79
80
81
82
# File 'lib/stoplight/infrastructure/memory/storage/window_metrics.rb', line 78

def clear
  mutex.synchronize do
    initialize_metrics
  end
end

#metrics_snapshotObject

Get metrics for the current light



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/stoplight/infrastructure/memory/storage/window_metrics.rb', line 29

def metrics_snapshot
  mutex.synchronize do
    window_start = (clock.current_time - @window_size)
    errors = @errors.sum_in_window(window_start)
    successes = @successes.sum_in_window(window_start)

    Domain::MetricsSnapshot.new(
      errors:,
      successes:,
      consecutive_errors: [@consecutive_errors, errors].min,
      consecutive_successes: [@consecutive_successes, successes].min,
      last_error: @last_error,
      last_success_at: @last_success_at
    )
  end
end

#record_failure(exception) ⇒ Object

Records failed circuit breaker execution



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/stoplight/infrastructure/memory/storage/window_metrics.rb', line 62

def record_failure(exception)
  mutex.synchronize do
    @errors.increment

    failure = Domain::Failure.from_error(exception, time: clock.current_time)
    last_error_at = @last_error&.occurred_at

    if last_error_at.nil? || failure.occurred_at > last_error_at
      @last_error = failure
    end

    @consecutive_errors += 1
    @consecutive_successes = 0
  end
end

#record_successObject

Records successful circuit breaker execution



47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/stoplight/infrastructure/memory/storage/window_metrics.rb', line 47

def record_success
  mutex.synchronize do
    current_time = clock.current_time
    @successes.increment

    if @last_success_at.nil? || current_time > T.must(@last_success_at)
      @last_success_at = current_time
    end

    @consecutive_errors = 0
    @consecutive_successes += 1
  end
end