Class: AttemptThis::AttemptObject

Inherits:
Object
  • Object
show all
Defined in:
lib/attempt_this/attempt_object.rb

Overview

Retry policy implementation. This class is internal and is not supposed to be used outside of the module.

Constant Summary collapse

@@scenarios =

All registered scenarios

{}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(enumerator) ⇒ AttemptObject

Initializes object with enumerator.



22
23
24
# File 'lib/attempt_this/attempt_object.rb', line 22

def initialize(enumerator)
  @enumerator = enumerator
end

Class Method Details

.get_object(id_or_enumerator) ⇒ Object



15
16
17
18
19
# File 'lib/attempt_this/attempt_object.rb', line 15

def self.get_object(id_or_enumerator)
  impl = @@scenarios[id_or_enumerator]
  impl ||= AttemptObject.new(id_or_enumerator)
  impl
end

.resetObject

Resets all static data.



11
12
13
# File 'lib/attempt_this/attempt_object.rb', line 11

def self.reset
  @@scenarios = {}
end

Instance Method Details

#and_default_to(default_method, &block) ⇒ Object

Specifies default method that should be called after all attempts have failed.

Raises:

  • (ArgumentError)


75
76
77
78
79
80
81
# File 'lib/attempt_this/attempt_object.rb', line 75

def and_default_to(default_method, &block)
  raise(ArgumentError, 'Default method is nil!') unless default_method
  raise(ArgumentError, 'Default method has already been specified!') if @default_method

  @default_method = default_method
  attempt(block)
end

#attempt(block) ⇒ Object

Executes the code block.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/attempt_this/attempt_object.rb', line 27

def attempt(block)
  # Returning self will allow chaining calls
  return self unless block
  return block.call unless AttemptThis.enabled?

  apply_defaults

  # Retriable attempts require special error handling
  result = each_retriable_attempt do
    return attempt_with_reset(&block)
  end

  # Final attempt
  if (result != :empty)
    @delay_policy.call unless result == :skipped
    final_attempt(&block)
  end
end

#scenario(id) ⇒ Object

Creates a scenario with the given id.

Raises:

  • (ArgumentError)


108
109
110
111
112
113
# File 'lib/attempt_this/attempt_object.rb', line 108

def scenario(id)
  raise(ArgumentError, 'Nil id!') if id.nil?
  raise(ArgumentError, "There is already a scenario with id #{id}") if @@scenarios.has_key?(id)

  @@scenarios[id] = self
end

#with_binary_backoff(initial_delay, &block) ⇒ Object

Specifies delay which doubles between failed attempts.

Raises:

  • (ArgumentError)


84
85
86
87
88
89
90
91
# File 'lib/attempt_this/attempt_object.rb', line 84

def with_binary_backoff(initial_delay, &block)
  raise(ArgumentError, "Delay should be a number; got ${initial_delay}!") unless initial_delay.is_a?(Numeric)
  raise(ArgumentError, "Delay should be a positive number; got #{initial_delay}!") unless initial_delay > 0
  raise(ArgumentError, "Delay policy has already been specified!") if @delay_policy

  @delay_policy = BinaryBackoffPolicy.new(initial_delay)
  attempt(block)
end

#with_delay(delay, &block) ⇒ Object

Specifies delay in seconds between failed attempts.

Raises:

  • (ArgumentError)


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/attempt_this/attempt_object.rb', line 47

def with_delay(delay, &block)
  # Delay should be either an integer or a range of integers.
  if (delay.is_a?(Numeric))
    raise(ArgumentError, "Delay should be a non-negative number; got #{delay}!") unless delay >= 0
    delay = delay..delay
  elsif delay.is_a?(Range)
    raise(ArgumentError, "Range members should be numbers; got #{delay}!") unless delay.first.is_a?(Numeric) && delay.last.is_a?(Numeric)
    raise(ArgumentError, "Range members should be non-negative; got #{delay}!") unless delay.first >= 0 && delay.last >= 0
    raise(ArgumentError, "Range's end should be greater than or equal to range's start; got #{delay}!") unless delay.first <= delay.last
  else
    raise(ArgumentError, "Delay should be either an number or a range of numbers; got #{delay}!")
  end
  raise(ArgumentError, 'Delay policy has already been specified!') if @delay_policy
  @delay_policy = lambda{Kernel.sleep(delay.first + rand(delay.count))}

  attempt(block)
end

#with_filter(*exceptions, &block) ⇒ Object

Specifies exceptions

Raises:

  • (ArgumentError)


94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/attempt_this/attempt_object.rb', line 94

def with_filter(*exceptions, &block)
  raise(ArgumentError, "Empty exceptions list!") unless exceptions.size > 0
  # Everything must be an exception.
  exceptions.each do |e|
    raise(ArgumentError, "Not an exception: #{e}!") unless e <= Exception
  end

  raise(ArgumentError, "Exception filter has already been specified!") if @exception_filter

  @exception_filter = ExceptionTypeFilter.new(exceptions)
  attempt(block)
end

#with_reset(reset_method, &block) ⇒ Object

Specifies reset method that will be called after each failed attempt.

Raises:

  • (ArgumentError)


66
67
68
69
70
71
72
# File 'lib/attempt_this/attempt_object.rb', line 66

def with_reset(reset_method, &block)
  raise(ArgumentError, 'Reset method is nil!') unless reset_method
  raise(ArgumentError, 'Reset method has already been speicifed!') if @reset_method

  @reset_method = reset_method
  attempt(block)
end