Class: Seekmodo::Sdk::CircuitBreaker

Inherits:
Object
  • Object
show all
Defined in:
lib/seekmodo/sdk/circuit_breaker.rb

Constant Summary collapse

STATE_CLOSED =
"closed"
STATE_OPEN =
"open"
STATE_HALFOPEN =
"half_open"

Instance Method Summary collapse

Constructor Details

#initialize(store, key: "numinix.seekmodo.circuit", failure_threshold: 5, failure_window_seconds: 60, open_cooldown_seconds: 30, clock: nil) ⇒ CircuitBreaker

Returns a new instance of CircuitBreaker.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/seekmodo/sdk/circuit_breaker.rb', line 12

def initialize(
  store,
  key: "numinix.seekmodo.circuit",
  failure_threshold: 5,
  failure_window_seconds: 60,
  open_cooldown_seconds: 30,
  clock: nil
)
  @store = store
  @key = key
  @failure_threshold = failure_threshold
  @failure_window_seconds = failure_window_seconds
  @open_cooldown_seconds = open_cooldown_seconds
  @clock = clock || -> { Time.now.to_i }
end

Instance Method Details

#allow_request?Boolean

Returns:

  • (Boolean)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/seekmodo/sdk/circuit_breaker.rb', line 28

def allow_request?
  state = load_state
  now = @clock.call

  if state["state"] == STATE_OPEN
    if now - state["opened_at"].to_i >= @open_cooldown_seconds
      state["state"] = STATE_HALFOPEN
      state["probe_in_flight"] = true
      save_state(state)
      return true
    end
    return false
  end

  if state["state"] == STATE_HALFOPEN
    return false if state["probe_in_flight"]

    state["probe_in_flight"] = true
    save_state(state)
    return true
  end

  true
end

#record_failureObject



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/seekmodo/sdk/circuit_breaker.rb', line 71

def record_failure
  state = load_state
  now = @clock.call

  if state["state"] == STATE_HALFOPEN
    save_state(
      "state" => STATE_OPEN,
      "failures" => [],
      "opened_at" => now,
      "probe_in_flight" => false
    )
    return
  end

  failures = state["failures"] + [now]
  cutoff = now - @failure_window_seconds
  failures = failures.select { |ts| ts >= cutoff }

  if failures.length >= @failure_threshold
    save_state(
      "state" => STATE_OPEN,
      "failures" => [],
      "opened_at" => now,
      "probe_in_flight" => false
    )
    return
  end

  state["failures"] = failures
  save_state(state)
end

#record_successObject



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/seekmodo/sdk/circuit_breaker.rb', line 53

def record_success
  state = load_state
  if [STATE_HALFOPEN, STATE_OPEN].include?(state["state"])
    save_state(
      "state" => STATE_CLOSED,
      "failures" => [],
      "opened_at" => 0,
      "probe_in_flight" => false
    )
    return
  end

  if state["failures"].any?
    state["failures"] = []
    save_state(state)
  end
end

#snapshotObject



107
108
109
# File 'lib/seekmodo/sdk/circuit_breaker.rb', line 107

def snapshot
  load_state
end

#stateObject



103
104
105
# File 'lib/seekmodo/sdk/circuit_breaker.rb', line 103

def state
  load_state["state"]
end