lib/attempt.rb in attempt-0.2.0 vs lib/attempt.rb in attempt-0.2.1

- old
+ new

@@ -2,114 +2,114 @@ require 'structured_warnings' # The Attempt class encapsulates methods related to multiple attempts at # running the same method before actually failing. class Attempt - - # The version of the attempt library. - VERSION = '0.2.0' - # Warning raised if an attempt fails before the maximum number of tries - # has been reached. - class Warning < StandardWarning; end - - # Number of attempts to make before failing. The default is 3. - attr_accessor :tries - - # Number of seconds to wait between attempts. The default is 60. - attr_accessor :interval - - # A boolean value that determines whether errors that would have been - # raised should be sent to STDERR as warnings. The default is true. - attr_accessor :warnings - - # If you provide an IO handle to this option then errors that would - # have been raised are sent to that handle. - attr_accessor :log - - # If set, this increments the interval with each failed attempt by that - # number of seconds. - attr_accessor :increment - - # If set, the code block is further wrapped in a timeout block. - attr_accessor :timeout - - # Determines which exception level to check when looking for errors to - # retry. The default is 'Exception' (i.e. all errors). - attr_accessor :level - - # :call-seq: - # Attempt.new{ |a| ... } - # - # Creates and returns a new +Attempt+ object. Use a block to set the - # accessors. - # - def initialize - @tries = 3 # Reasonable default - @interval = 60 # Reasonable default - @log = nil # Should be an IO handle, if provided - @increment = nil # Should be an int, if provided - @timeout = nil # Wrap the code in a timeout block if provided - @level = Exception # Level of exception to be caught - @warnings = true # Errors sent to STDERR as warnings if true - - yield self if block_given? + # The version of the attempt library. + VERSION = '0.2.1' + + # Warning raised if an attempt fails before the maximum number of tries + # has been reached. + class Warning < StandardWarning; end + + # Number of attempts to make before failing. The default is 3. + attr_accessor :tries + + # Number of seconds to wait between attempts. The default is 60. + attr_accessor :interval + + # A boolean value that determines whether errors that would have been + # raised should be sent to STDERR as warnings. The default is true. + attr_accessor :warnings + + # If you provide an IO handle to this option then errors that would + # have been raised are sent to that handle. + attr_accessor :log + + # If set, this increments the interval with each failed attempt by that + # number of seconds. + attr_accessor :increment + + # If set, the code block is further wrapped in a timeout block. + attr_accessor :timeout + + # Determines which exception level to check when looking for errors to + # retry. The default is 'Exception' (i.e. all errors). + attr_accessor :level + + # :call-seq: + # Attempt.new{ |a| ... } + # + # Creates and returns a new +Attempt+ object. Use a block to set the + # accessors. + # + def initialize + @tries = 3 # Reasonable default + @interval = 60 # Reasonable default + @log = nil # Should be an IO handle, if provided + @increment = nil # Should be an int, if provided + @timeout = nil # Wrap the code in a timeout block if provided + @level = Exception # Level of exception to be caught + @warnings = true # Errors sent to STDERR as warnings if true + + yield self if block_given? end - - # Attempt to perform the operation in the provided block up to +tries+ - # times, sleeping +interval+ between each try. - # - # You will not typically use this method directly, but the Kernel#attempt - # method instead. - # - def attempt - count = 1 - begin - if @timeout - Timeout.timeout(@timeout){ yield } - else - yield - end - rescue @level => error - @tries -= 1 - if @tries > 0 - msg = "Error on attempt # #{count}: #{error}; retrying" - count += 1 - warn Warning, msg if @warnings - @log.puts msg if @log - @interval += @increment if @increment - sleep @interval - retry - end - raise + + # Attempt to perform the operation in the provided block up to +tries+ + # times, sleeping +interval+ between each try. + # + # You will not typically use this method directly, but the Kernel#attempt + # method instead. + # + def attempt + count = 1 + begin + if @timeout + Timeout.timeout(@timeout){ yield } + else + yield end - end + rescue @level => error + @tries -= 1 + if @tries > 0 + msg = "Error on attempt # #{count}: #{error}; retrying" + count += 1 + warn Warning, msg if @warnings + @log.puts msg if @log + @interval += @increment if @increment + sleep @interval + retry + end + raise + end + end end module Kernel # :call-seq: # attempt(tries = 3, interval = 60, timeout = nil){ # some op } - # + # # Attempt to perform the operation in the provided block up to +tries+ # times, sleeping +interval+ between each try. By default the number # of tries defaults to 3, the interval defaults to 60 seconds, and there # is no timeout specified. - # + # # If +timeout+ is provided then the operation is wrapped in a Timeout # block as well. This is handy for those rare occasions when an IO # connection could hang indefinitely, for example. - # + # # If the operation still fails the (last) error is then re-raised. # # This is really just a wrapper for Attempt.new where the simple case is # good enough i.e. you don't care about warnings, increments or logging, # and you want a little added convenience. # # Example: # # # Make 3 attempts to connect to the database, 60 seconds apart. # attempt{ DBI.connect(dsn, user, passwd) } - # + # def attempt(tries = 3, interval = 60, timeout = nil, &block) raise 'no block given' unless block_given? Attempt.new{ |a| a.tries = tries a.interval = interval