Module: Retriable

Defined in:
lib/retriable.rb,
lib/retriable/config.rb,
lib/retriable/version.rb,
lib/retriable/validation.rb,
lib/retriable/exponential_backoff.rb

Defined Under Namespace

Modules: Validation Classes: Config, ExponentialBackoff

Constant Summary collapse

OVERRIDE_THREAD_KEY =

Thread-local storage key for the active #with_override block. We deliberately use Thread#thread_variable_set/get (true thread-local) rather than Thread.current[] (fiber-local) so that fibers within a thread share the same override. Changing this to Thread.current[] would silently break callers that use fiber-based concurrency.

:retriable_override
VERSION =
"4.0.0"

Class Method Summary collapse

Class Method Details

.configObject



24
25
26
# File 'lib/retriable.rb', line 24

def config
  @config ||= Config.new
end

.configure {|config| ... } ⇒ Object

Yields:



20
21
22
# File 'lib/retriable.rb', line 20

def configure
  yield(config)
end

.retriable(opts = {}) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/retriable.rb', line 56

def retriable(opts = {}, &)
  override_config = current_override
  local_config = if opts.empty? && !override_config
                   config
                 else
                   Config.new(apply_override_options(config.to_h.merge(opts), override_config))
                 end

  # Config is mutable through `configure`, so validate again immediately before use.
  local_config.validate!

  plan = retry_plan(local_config)
  on = local_config.on
  retry_if = local_config.retry_if
  on_retry = local_config.on_retry
  on_give_up = local_config.on_give_up
  sleep_disabled = local_config.sleep_disabled
  max_elapsed_time = local_config.max_elapsed_time

  exception_list = on.is_a?(Hash) ? on.keys : on
  exception_list = [*exception_list]
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elapsed_time = -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time }

  execute_tries(
    max_tries: plan.max_tries, interval_for: plan.interval_for,
    exception_list: exception_list, on: on, retry_if: retry_if, on_retry: on_retry,
    on_give_up: on_give_up, elapsed_time: elapsed_time, max_elapsed_time: max_elapsed_time,
    sleep_disabled: sleep_disabled, &
  )
end

.with_context(context_key, options = {}) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/retriable.rb', line 43

def with_context(context_key, options = {}, &)
  contexts = available_contexts

  if !contexts.key?(context_key)
    raise ArgumentError,
          "#{context_key} not found in Retriable contexts (including overrides). Available contexts: #{contexts.keys}"
  end

  return unless block_given?

  retriable(context_options_for(context_key, options), &)
end

.with_override(opts = {}) ⇒ Object

Raises:

  • (ArgumentError)


28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/retriable.rb', line 28

def with_override(opts = {})
  raise ArgumentError, "empty override options are not allowed" if opts.empty?
  raise ArgumentError, "with_override requires a block" unless block_given?

  validate_override_options(opts)

  previous = Thread.current.thread_variable_get(OVERRIDE_THREAD_KEY)
  Thread.current.thread_variable_set(OVERRIDE_THREAD_KEY, opts)
  begin
    yield
  ensure
    Thread.current.thread_variable_set(OVERRIDE_THREAD_KEY, previous)
  end
end