何の機能か?
AWSのAPIは、基本的にあるリクエストに対するレスポンスを即座に返してしまい、そのリクエストで意図した結果が必ず起こるとは限りません。
APIリクエストに成功すると、HTTPコード200 とともにインスタンスの情報が返ってきます。
ですが、HTTP 200を受け取ったからといって、このインスタンスがrunningになるとは限りません。
APIレスポンスが返ってきた後、その対象が望むべきStatusになっているかどうかを暫くの間監視しておく必要があります。
このような場合aws-sdk v2から導入されたwaitersを使うと便利です。
まずv2をインストール
gem 'aws-sdk', '2.0.11.pre'
gem 'aws-sdk-core'
環境変数をセットしておくこと
$ export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXX
$ export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
$ export AWS_REGION=ap-northeast-1
使い方の例
簡単な使い方
wait_untilメソッドで処理をブロックしています。
require 'aws-sdk'
ec2 = Aws::EC2::Client.new
ec2.start_instances(instance_ids: ['i-12345678'])
ec2.wait_until(:instance_running, instance_ids:['i-12345678'])
waitの細かい制御方法
以下のケースは一時間ec2が起動するまで待つ例です。(15秒おきに240回待つ)
ec2 = Aws::EC2::Client.new
ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w|
w.interval = 15
w.max_attempts = 240
end
RDSでDBがavailableになるまで待つ
rds.create_db_instance(db_instance_identifier:'db01')
rds.wait_until(:db_instance_available, db_instance_identifier:'db01')
- 与えるパラメータもResourceによって違うので注意
interval毎に処理を挟む
ec2 = Aws::EC2::Client.new
ec2.wait_until(:instance_running, instance_ids:['i-12345678']) do |w|
w.before_attempt do |attempt|
puts "before interval..."
end
w.before_wait do |attempt, prev_response|
puts "after interval..."
end
end
- before_waitはintervalの後に処理を挟むことが出来る
- before_attemptはintervalの前に処理を挟むことが出来る
rescueでエラーを拾う
指定時間待ってもステータスが変わらない場合、Aws::Waiters::Errors::WaiterFailedが発生する。
ec2 = Aws::EC2::Client.new
begin
ec2.wait_until(:instance_running, instance_ids:['i-1234567']) do |w|
w.interval = 15
w.max_attempts = 240
end
rescue Aws::Waiters::Errors::WaiterFailed => error
puts "failed waiting for instance running: #{error.message}"
end
Resource別statusの確認
主なResourceのstatusを調べてみる。
wait_untilの引数にすればそのステータスになるまで処理をブロックできます。
EC2
Aws::EC2::Client.new.waiter_names
=> [:system_status_ok,
:instance_status_ok,
:image_available,
:instance_running,
:instance_stopped,
:instance_terminated,
:export_task_completed,
:export_task_cancelled,
:snapshot_completed,
:subnet_available,
:volume_available,
:volume_in_use,
:volume_deleted,
:vpc_available,
:vpn_connection_available,
:vpn_connection_deleted,
:bundle_task_complete,
:conversion_task_completed,
:conversion_task_cancelled,
:customer_gateway_available,
:conversion_task_deleted,
:spot_instance_request_fulfilled]
S3
Aws::S3::Client.new.waiter_names
=> [:bucket_exists, :bucket_not_exists, :object_exists, :object_not_exists]
RDS
Aws::RDS::Client.new.waiter_names
=> [:db_instance_available, :db_instance_deleted]
Redshift
Aws::Redshift::Client.new.waiter_names
=> [:cluster_available, :cluster_deleted, :snapshot_available]
DynamoDB
Aws::DynamoDB::Client.new.waiter_names
=> [:table_exists, :table_not_exists]
ステータスが存在しないケース
Aws::EMR::Client.new.waiter_names
=> []
- ElastiCache、Kinesis、SQSなどもステータスが存在しません。
まとめ
APIリクエスト後Statusの値をintervalを設けてPollingし、何回以内に成功しなければ異常と判断されるので例外を投げると言った処理を自分で作っていたかと思うのですが、その部分をSDKで吸収してくれるようになりました。