Module: Patiently::Helpers
- Defined in:
- lib/patiently/helpers.rb
Overview
Mix this into a class (or configure RSpec to include it) to gain the #patiently and #patiently_until helpers:
include Patiently::Helpers
Constant Summary collapse
- IN_PATIENTLY =
Thread-local flag marking that we are already inside a
patientlyblock. Nested blocks are run once and let the outer block do the retrying. :patiently_in_progress- RetryUntilTrue =
Internal sentinel used by #patiently_until to signal "not truthy yet".
Class.new(StandardError)
Instance Method Summary collapse
-
#patiently(timeout = nil, &block) ⇒ Object
Runs
block, retrying it whenever it raises, until it succeeds or the patience window (timeout + min/max retries) is exhausted. -
#patiently_until(timeout = nil, &block) ⇒ Object
(also: #patiently_wait_until)
Retries
blockuntil it returns a truthy value or the patience window elapses, then returns the final result as a boolean.
Instance Method Details
#patiently(timeout = nil, &block) ⇒ Object
Runs block, retrying it whenever it raises, until it succeeds or the
patience window (timeout + min/max retries) is exhausted. Returns the
block's return value on success; re-raises the last exception on failure.
When called while another patiently block is already running on the
current thread, the block is simply run once: only the outermost block is
retried.
rubocop:disable Lint/RescueException
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/patiently/helpers.rb', line 26 def patiently(timeout = nil, &block) return block.call if Thread.current[IN_PATIENTLY] config = Patiently.config timeout ||= config.timeout started_at = monotonic_time retries = 0 begin Thread.current[IN_PATIENTLY] = true attempt_started_at = monotonic_time block.call rescue Exception => e elapsed = attempt_started_at - started_at timed_out = elapsed > timeout && retries >= config.min_retries retries_exhausted = config.max_retries && retries >= config.max_retries raise e if timed_out || retries_exhausted sleep(config.retry_interval(retries)) if monotonic_time == started_at raise Patiently::FrozenInTime, "time appears to be frozen, consider time travelling instead" end retries += 1 retry ensure Thread.current[IN_PATIENTLY] = false end end |
#patiently_until(timeout = nil, &block) ⇒ Object Also known as: patiently_wait_until
Retries block until it returns a truthy value or the patience window
elapses, then returns the final result as a boolean.
Because patiently only retries on a raise, we raise an internal
sentinel while the block is falsey and translate a timed-out sentinel back
into false. A real exception inside the block is not the sentinel, so it
still propagates.
67 68 69 70 71 72 |
# File 'lib/patiently/helpers.rb', line 67 def patiently_until(timeout = nil, &block) patiently(timeout) { block.call || raise(RetryUntilTrue) } true rescue RetryUntilTrue false end |