We’ve added a feature called Waiters to the v2 AWS SDK for Ruby, and I am pretty excited about it. A waiter is a simple abstraction around the pattern of polling an AWS API until a desired state is reached.
This simple example shows how to use waiters to block until a particular EC2 instance is running:
ec2 = Aws::EC2::Client.new ec2.wait_until(:instance_running, instance_ids:['i-12345678'])
Waiters will not wait indefinitely and can fail. Each waiter has a default polling interval and maximum number of attempts to make. If a waiter encounters an unexpected error or fails to reach the desired condition in time it will raise an error:
begin ec2.wait_until(:instance_running, instance_ids:['i-12345678']) resuce Aws::Waiters::Errors::WaiterFailed # oops end
You can modify the default interval and wait time between attempts by passing a block.
# this will wait upto ~ one hour ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| # seconds between each attempt w.interval = 15 # maximum number of polling attempts before giving up w.max_attempts = 240 end
In addition to interval and maximum attempts, you can configure callbacks to trigger before each attempt polling attempt and before sleeping between attempts.
ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| w.before_attempt do |n| # n - the number of attempts made end w.before_wait do |n, resp| # n - the number of attempts made # resp -the client response from the previous attempt end end
You can throw
from these callbacks to stop the waiter immediately. You can use this to write you own delay and back-off logic.
Here I am using a callback to perform exponential back-off between polling attempts:
ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| w.interval = 0 # disable normal sleep w.before_wait do |n, resp| sleep(n ** 2) end end
This example gives up after one hour.
ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w| one_hour_later = Time.now + 3600 w.before_wait do |n, resp| throw :failure, 'waited too long' if Time.now > one_hour_later end end
Waiters and Resources, Looking Ahead
You may have noticed that some waiters have already been exposed to the resource classes.
ec2 = Aws::EC2::Resource.new instance = ec2.instance('i-12345678') instance.stop instance.wait_until_stopped puts instance.id + ' is stopped'
In addition to connecting more waiters and resources, I’m excited to look into batch waiters. Imagine the following use case:
instances = ec2.create_instances(min_count: 5, ...) instances.wait_until_running puts "the following new instances are now running:n" puts instances.map(&:id)
Waiters are documented in the Ruby SDK API reference. Each service client documents the
method and provides a list of available waiter names. Here are links to the
Give waiters a try and let us know what you think!