Module: Retry
- Defined in:
- lib/retry.rb
Overview
Support for performing retriable operations
Defined Under Namespace
Modules: Exceptions Classes: Engine, StopRetry
Class Method Summary collapse
-
.do(delay: nil, exceptions: nil, handlers: nil, tries: nil) ⇒ Object
Executes the code block until it returns successfully, throws a non-retriable exception or some termination condition is met.
-
.handle_exception(exception, handlers, tries, retriable) ⇒ Object
Executes a handler for an exception.
-
.handle_retry(exception, handlers, tries, retriable, delay) ⇒ Object
Executes the retry handler.
-
.handler(exception, handlers, tries, retriable, name = nil) ⇒ Object
Executes the specified handler.
-
.retry?(exception, exceptions, tries) ⇒ Boolean
Returns true if the exception instance is retriable, false if not.
-
.tries_remain?(exception, tries) ⇒ Boolean
Returns true if there are tries remaining.
-
.wait(delay) ⇒ void
Waits for the specified number of seconds.
Class Method Details
.do(delay: nil, exceptions: nil, handlers: nil, tries: nil) ⇒ Object
Executes the code block until it returns successfully, throws a non-retriable exception or some termination condition is met.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/retry.rb', line 76 def self.do(delay: nil, exceptions: nil, handlers: nil, tries: nil) yield if block_given? rescue StandardError => exception # Decrement the tries-remaining count if appropriate tries -= 1 if tries.is_a?(Numeric) # Handlers may raise StopRetry to force a return value from the method # Check if the exception is retriable retriable = retry?(exception, exceptions, tries) begin # Run the exception handler # - this will re-raise the exception if it is not retriable handle_exception(exception, handlers, tries, retriable) # Run the retry handler and retry handle_retry(exception, handlers, tries, retriable, delay) retry rescue StopRetry => exception # Force a return value from the handler exception.value end end |
.handle_exception(exception, handlers, tries, retriable) ⇒ Object
Executes a handler for an exception
104 105 106 107 108 109 110 111 |
# File 'lib/retry.rb', line 104 def self.handle_exception(exception, handlers, tries, retriable) # Execute the general exception handler handler(exception, handlers, tries, retriable, :all) # Execute the exception-specific handler handler(exception, handlers, tries, retriable) # Re-raise the exception if not retriable raise exception unless retriable end |
.handle_retry(exception, handlers, tries, retriable, delay) ⇒ Object
Executes the retry handler
119 120 121 122 123 124 |
# File 'lib/retry.rb', line 119 def self.handle_retry(exception, handlers, tries, retriable, delay) # Wait for the specified delay wait(delay) unless delay.zero? # Return the result of the retry handler handler(exception, handlers, tries, retriable, :retry) end |
.handler(exception, handlers, tries, retriable, name = nil) ⇒ Object
Executes the specified handler
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/retry.rb', line 134 def self.handler(exception, handlers, tries, retriable, name = nil) handler = nil if name.nil? # Find the handler for the exception class handlers.each do |e, h| next unless e.is_a?(Class) && exception.is_a?(e) handler = h break end # Use the default handler if no match was found handler ||= handlers[:default] else # Use the named handler, do not use the default if not found handler = handlers[name] end handler ? handler.call(exception, tries, retriable) : nil end |
.retry?(exception, exceptions, tries) ⇒ Boolean
Returns true if the exception instance is retriable, false if not
157 158 159 160 161 162 163 164 |
# File 'lib/retry.rb', line 157 def self.retry?(exception, exceptions, tries) # Return false if there are no more tries remaining return false unless tries_remain?(exception, tries) # Return true if the exception matches a retriable exception class exceptions.each { |e| return true if exception.is_a?(e) } # The exception didn't match any retriable classes false end |
.tries_remain?(exception, tries) ⇒ Boolean
Returns true if there are tries remaining
170 171 172 173 174 175 176 177 178 |
# File 'lib/retry.rb', line 170 def self.tries_remain?(exception, tries) # If tries is numeric, this is the number of tries remaining return false if tries.is_a?(Numeric) && tries.zero? # If tries has a #call method, this should return true to allow a retry or # false to raise the exception return false if tries.respond_to?(:call) && !tries.call(exception) # Otherwise allow a retry true end |
.wait(delay) ⇒ void
This method returns an undefined value.
Waits for the specified number of seconds. If delay is positive, sleep for that period. If delay is negative, sleep for a random time up to that duration.
185 186 187 |
# File 'lib/retry.rb', line 185 def self.wait(delay) sleep(delay > 0 ? delay : Random.rand(-delay)) end |