Class: Retry

Inherits:
Object
  • Object
show all
Extended by:
Telemetry::Register
Includes:
Log::Dependency, Telemetry::Dependency
Defined in:
lib/retry/log.rb,
lib/retry/retry.rb,
lib/retry/telemetry.rb,
lib/retry/substitute.rb,
lib/retry/controls/time.rb,
lib/retry/controls/error.rb,
lib/retry/controls/receiver.rb,
lib/retry/controls/dependency.rb

Direct Known Subclasses

Substitute::Retry

Defined Under Namespace

Modules: Controls, Substitute, Telemetry Classes: Log

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Telemetry::Register

register_telemetry_sink

Instance Attribute Details

#action_executed(&action) ⇒ Object



6
7
8
9
10
11
12
# File 'lib/retry/retry.rb', line 6

def action_executed(&action)
  unless action.nil?
    self.action_executed = action
  end

  @action_executed
end

Class Method Details

.buildObject



15
16
17
# File 'lib/retry/retry.rb', line 15

def self.build
  instance = new
end

.call(*errors, millisecond_intervals: nil, &action) ⇒ Object



26
27
28
29
# File 'lib/retry/retry.rb', line 26

def self.call(*errors, millisecond_intervals: nil, &action)
  instance = build
  instance.(errors, millisecond_intervals: millisecond_intervals, &action)
end

.configure(receiver, attr_name: nil) ⇒ Object



19
20
21
22
23
24
# File 'lib/retry/retry.rb', line 19

def self.configure(receiver, attr_name: nil)
  attr_name ||= :rtry
  instance = build
  receiver.public_send("#{attr_name}=", instance)
  instance
end

Instance Method Details

#call(*errors, millisecond_intervals: nil, &action) ⇒ Object



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
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
# File 'lib/retry/retry.rb', line 31

def call(*errors, millisecond_intervals: nil, &action)
  errors = errors.flatten
  millisecond_intervals ||= [0]

  logger.trace { "Starting retry (Errors: #{errors.empty? ? '(none)' : errors.join(', ')}, Millisecond Intervals: #{millisecond_intervals.join(', ')})" }

  intervals = millisecond_intervals.to_enum

  cycle = 0

  error = nil
  probe = proc { |e| error = e }

  loop do
    success = Try.(errors, error_probe: probe) do
      logger.debug { "Attempting (Cycle: #{cycle})" }
      action.call(cycle)
    end

    action_executed&.call(cycle)

    if success
      logger.info { "Attempt succeeded (Cycle: #{cycle})" }
      telemetry.record :succeeded, Retry::Telemetry::Data::Succeeded.new(cycle)
      break
    end

    interval = intervals.next rescue nil

    logger.debug { "Attempt failed (Cycle: #{cycle}, Error: #{error.class.name})" }
    telemetry.record :failed, Retry::Telemetry::Data::Failed.new(cycle, error.class, interval)

    if interval.nil?
      logger.debug { "No more attempts. Intervals depleted." }
      break
    end

    logger.debug { "Will retry. Sleeping #{interval} milliseconds before next attempt." }
    sleep (interval/1000.0)

    cycle += 1
  end

  unless error.nil?
    logger.info { "Attempts failed. Will not retry. Raising error: #{error.class.name}. (Cycle: #{cycle})" }
    raise error
  end

  cycle
end