Public Class Methods

new(options = {}) click to toggle source

Creates a new Wait instance.

Basic Options


Number of times to attempt the block. Default is 5.


Seconds until the block times out. Default is 15.


Seconds to delay in between attempts. Default is 1.


One or an array of exceptions to rescue. Default is nil.


If true, debug logging is enabled. Default is false.

Advanced Options


Ruby logger used. Default is Wait::BaseLogger.


Strategy used to count attempts. Default is Wait::BaseCounter.


Strategy used to delay in between attempts. Default is Wait::RegularDelayer.


Strategy used to rescue exceptions. Default is Wait::BaseRescuer.


Strategy used to test the result. Default is Wait::TruthyTester.


Strategy used to raise specific exceptions. Default is Wait::SignalRaiser.

# File lib/wait.rb, line 48
def initialize(options = {})
  # Assign defaults.
  debug      = options[:debug]    || false
  @logger    = options[:logger]   || (debug ? DebugLogger : DEFAULT[:logger]).new
  attempts   = options[:attempts] || DEFAULT[:attempts]
  @counter   = options[:counter]  || DEFAULT[:counter].new(attempts)
  @timeout   = options[:timeout]  || DEFAULT[:timeout]
  delay      = options[:delay]    || DEFAULT[:delay]
  @delayer   = options[:delayer]  || DEFAULT[:delayer].new(delay)
  exceptions = options[:rescue]
  @rescuer   = options[:rescuer]  || DEFAULT[:rescuer].new(exceptions)
  @tester    = options[:tester]   || DEFAULT[:tester].new
  @raiser    = options[:raiser]   || DEFAULT[:raiser].new

  # Assign the logger to each of the strategies.
  [@counter, @delayer, @rescuer, @tester, @raiser].each do |strategy|
    strategy.logger = @logger if strategy.respond_to?(:logger=)

Public Instance Methods

until(&block) click to toggle source


Wait#until executes a block until there's a valid (by default, truthy) result. Useful for blocking script execution until:

  • an HTTP request was successful

  • a port has opened

  • a process has started

  • etc.


wait =
# => #<Wait>
wait.until { }
# [Counter] attempt 1/5
# [Tester]  result: false
# [Rescuer] rescued: Wait::ResultInvalid
# [Raiser]  not raising: Wait::ResultInvalid
# [Delayer] delaying for 1s
# [Counter] attempt 2/5
# [Tester]  result: true
# => true

If you wish to handle an exception by attempting the block again, pass one or an array of exceptions with the :rescue option.

wait = => RuntimeError)
# => #<Wait>
wait.until do |attempt|
  case attempt
  when 1 then nil
  when 2 then raise RuntimeError
  when 3 then "foo"
# [Counter] attempt 1/5
# [Tester]  result: nil
# [Rescuer] rescued: Wait::ResultInvalid
# [Raiser]  not raising: Wait::ResultInvalid
# [Delayer] delaying for 1s
# [Counter] attempt 2/5
# [Rescuer] rescued: RuntimeError
# [Raiser]  not raising: RuntimeError
# [Delayer] delaying for 1s
# [Counter] attempt 3/5
# [Tester]  result: "foo"
# => "foo"


The result of the block if valid (by default, truthy).


If no results are valid, the exception from the last attempt made.

# File lib/wait.rb, line 124
def until(&block)
  # Reset the attempt counter.
    # Increment the attempt counter.
    # Wrap the given block in a timeout.
    result = Timeout.timeout(@timeout, TimeoutError) do
      # Execute the block and pass the attempt count (an +Integer+) to it.
    # Raise an exception unless the result is valid.
    @tester.valid?(result) ? result : raise(ResultInvalid)
  rescue TimeoutError, ResultInvalid, *@rescuer.exceptions => exception
    # Log the exception.
    # Raise the exception if it ought to be.
    raise(exception) if @raiser.raise?(exception)
    # Raise the exception if this was the last attempt.
    raise(exception) if @counter.last_attempt?
    # Sleep before the next attempt.
    # Try the block again.


Generated with the Darkfish Rdoc Generator 2.