Class: Wurk::Swarm::Backoff
- Inherits:
-
Object
- Object
- Wurk::Swarm::Backoff
- Defined in:
- lib/wurk/swarm/backoff.rb
Overview
Per-key exponential backoff timer with survival-based reset. Pure
bookkeeping — no sleeping, no I/O — so the supervise thread never blocks
on it: it records a failure, then asks ready? each tick and acts only
once the delay has elapsed.
Delay grows base → 2·base → 4·base … capped at cap. A key whose child
survived at least reset_after seconds counts as a fresh first failure,
so a slot that ran healthily for a while doesn't inherit an old crash
streak. Keyed by slot index for crash-respawn and (in Swarm::Restart) for
replacement-retry delays.
Constant Summary collapse
- BASE =
1.0- CAP =
30.0- RESET_AFTER =
60.0
Instance Method Summary collapse
-
#clear(key) ⇒ Object
Forget the key entirely (slot retired or restart succeeded).
-
#consume(key) ⇒ Object
Mark the scheduled retry as issued without resetting the streak, so a child that crashes straight back escalates toward the cap.
-
#fail(key, lifetime: 0.0) ⇒ Object
Record a failure and schedule the next attempt.
-
#initialize(base: BASE, cap: CAP, reset_after: RESET_AFTER, clock: nil) ⇒ Backoff
constructor
A new instance of Backoff.
-
#pending?(key) ⇒ Boolean
A retry is scheduled and not yet issued.
-
#ready?(key) ⇒ Boolean
The scheduled delay has elapsed (or nothing is scheduled).
Constructor Details
#initialize(base: BASE, cap: CAP, reset_after: RESET_AFTER, clock: nil) ⇒ Backoff
Returns a new instance of Backoff.
20 21 22 23 24 25 26 27 |
# File 'lib/wurk/swarm/backoff.rb', line 20 def initialize(base: BASE, cap: CAP, reset_after: RESET_AFTER, clock: nil) @base = base @cap = cap @reset_after = reset_after @clock = clock || -> { ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) } @streak = Hash.new(0) @due_at = {} end |
Instance Method Details
#clear(key) ⇒ Object
Forget the key entirely (slot retired or restart succeeded).
58 59 60 61 |
# File 'lib/wurk/swarm/backoff.rb', line 58 def clear(key) @streak.delete(key) @due_at.delete(key) end |
#consume(key) ⇒ Object
Mark the scheduled retry as issued without resetting the streak, so a child that crashes straight back escalates toward the cap.
53 54 55 |
# File 'lib/wurk/swarm/backoff.rb', line 53 def consume(key) @due_at.delete(key) end |
#fail(key, lifetime: 0.0) ⇒ Object
Record a failure and schedule the next attempt. lifetime is how long
the failed child lived; >= reset_after resets the streak. Returns the
delay applied.
32 33 34 35 36 37 38 |
# File 'lib/wurk/swarm/backoff.rb', line 32 def fail(key, lifetime: 0.0) @streak[key] = 0 if lifetime >= @reset_after @streak[key] += 1 delay = [@base * (2**(@streak[key] - 1)), @cap].min @due_at[key] = now + delay delay end |
#pending?(key) ⇒ Boolean
A retry is scheduled and not yet issued.
41 42 43 |
# File 'lib/wurk/swarm/backoff.rb', line 41 def pending?(key) @due_at.key?(key) end |
#ready?(key) ⇒ Boolean
The scheduled delay has elapsed (or nothing is scheduled).
46 47 48 49 |
# File 'lib/wurk/swarm/backoff.rb', line 46 def ready?(key) at = @due_at[key] at.nil? || now >= at end |