lib/attempt.rb in attempt-0.1.0 vs lib/attempt.rb in attempt-0.1.1
- old
+ new
@@ -1,99 +1,105 @@
-require 'timeout'
-
-class Attempt
- VERSION = '0.1.0'
-
- # 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
-
- 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 msg if @warnings
- @log.puts msg if @log
- @interval += @increment if @increment
- sleep @interval
- retry
- end
- raise
- end
- end
-end
-
-module Kernel
- # 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.
- #
- 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
- a.timeout = timeout if timeout
- }.attempt(&block)
- end
-end
\ No newline at end of file
+require 'timeout'
+
+class Attempt
+ VERSION = '0.1.1'
+
+ # 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
+
+ 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 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
+ a.timeout = timeout if timeout
+ }.attempt(&block)
+ end
+end