Method: Wait#until

Defined in:
lib/wait.rb

#until(&block) ⇒ Object

Description

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.

Examples

wait = Wait.new
# => #<Wait>
wait.until { Time.now.sec.even? }
# [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 = Wait.new(:rescue => RuntimeError)
# => #<Wait>
wait.until do |attempt|
  case attempt
  when 1 then nil
  when 2 then raise RuntimeError
  when 3 then "foo"
  end
end
# [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"

Returns

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

Raises

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



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/wait.rb', line 124

def until(&block)
  # Reset the attempt counter.
  @counter.reset
  begin
    # Increment the attempt counter.
    @counter.increment
    # 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.
      yield(@counter.attempt)
    end
    # Raise an exception unless the result is valid.
    @tester.valid?(result) ? result : raise(ResultInvalid)
  rescue TimeoutError, ResultInvalid, *@rescuer.exceptions => exception
    # Log the exception.
    @rescuer.log(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.
    @delayer.sleep
    # Try the block again.
    retry
  end
end