ちょっと話題の記事

AWS SDK for Ruby version2 Released!

2014.09.26

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。望月です。
全国3000万人のAWS SDK for Rubyファンの皆様お待たせしました。本日ついにAWS SDK for RubyのメジャーバージョンアップであるAWS SDK for Ruby 2(以下 SDK v2)がリリースされました。

今までもDeveloper Previewとしてリリースされていましたが、これで正式版となったわけです。今日はインストール方法とバージョン2での新機能、今までのAWS SDK for Ruby(以下SDK v1)との違いなどについて私が気付いた点をまとめたいと思います。

インストール

以前までと同様、Rubygemsによってホストされていますので、gemコマンドでインストールします。ただしgem名はaws-sdk-coreとなっていますので注意して下さい。

$ gem install aws-sdk-core
...
$ ruby -r aws-sdk-core -e 'puts Aws::VERSION'
2.0.0

正常にインストールされた場合、バージョン番号が表示されると思います。

新機能

特筆すべきfeatureはほとんどREADMEに書かれているので、それを試してみました。

簡単なページング

APIリクエストに対して大量の結果が返される場合、一度に返される量を制限する必要があります。例えばS3のListObjectsの場合、API上ではtokenとして表現されているので、AWS CLIでは以下のような感じになります。

$ aws s3api list-objects --bucket mochizuki-bucket --profile default --max-items 10
{
    "NextToken": "None___10",
    "CommonPrefixes": [],
    "Contents": [
    <10個分のObject>
    ]
}
# 前のAPIレスポンスのNextTokenを指定
$ aws s3api list-objects --bucket mochizuki-bucket --profile default --max-items 10 --starting-token None___10
{
    "NextToken": "None___20",
    "CommonPrefixes": [],
    "Contents": [
    <10個分のObject>
    ]
}

SDK v1 で記載すると、毎回リクエストの度にmarkerを取得し、パラメータにセットし、APIリクエストを実行する、という必要があり非常に面倒でした。ですが、SDK v2でPageableResponseクラスというものが作成され、そのレスポンスクラスがページング処理のための便利な機能を持っています。実際にコードを見てみましょう。

require 'aws-sdk-core'

s3 = Aws::S3::Client.new

resp = s3.list_objects(bucket: 'mochizuki-bucket', max_keys: "10")
resp.contents.each{ |obj| puysobj[:key] }

# 続きがあるかどうかを判定
until resp.last_page?
  resp = resp.next_page # 次のリソースを取得 = APIコール実施
  resp.contents.each{ |obj| puts c[:key] }
end

last_page?next_pageを利用しました。意味は名前を見ると通じるかと思いますが、last_page?はこれが最後の取得出来るリソースかどうかを判定し、next_pageで次の10個のリソースを取得しています。これ以上取得できるリソースがない状態でnext_pageを実行すると、LastPageErrorが発生するので注意しましょう。

また、each_pageという、全ページを順番に取得して処理を実施するメソッドも用意されています。全リソースに対して必ず処理を実施する場合はかなり便利だと思います。上の例は、以下の様に書きなおすことが出来ます。

require 'aws-sdk-core'

s3 = Aws::S3::Client.new

s3.list_objects(bucket: 'mochizuki-bucket', max_keys: "10").each_page do |resp|
  puts resp.contents.map{ |obj| obj[:key] }
end

だいぶ記述がすっきりしました!

Waiters

AWSのAPIは、基本的にあるリクエストに対するレスポンスを即座に返しますが、そのリクエストで意図した結果が必ず起こるとは限らない、というところには注意が必要です。例えばstart-instancesというAPIは、Stop状態のEC2インスタンスを起動するためのAPIです。APIリクエストに成功すると、HTTPコード200 とともにインスタンスの情報が返ってきます。ですが、HTTP 200を受け取ったからといって、このインスタンスがrunningになるとは限りません。例えば起動処理中にAWSのデータセンターに隕石が落ちてDCが破損した場合(参考)、そのEC2の最終的な状態は保証できません。
何が言いたいかというと、APIレスポンスが返ってきた後、その対象が望むべきStatusになっているかどうかを暫くの間監視しておく必要があるのです。 これを普通にやろうとすると、APIリクエスト後、定期的にdescribe-instanceを叩いてStatusの値をチェックして、何回以内に成功しなければ異常と判断されるので例外を投げる、、等、だいぶ面倒なのですが、SDK v2では各サービスのクライアントクラスにwait_untilというメソッドが追加され、このあたりの制御が簡単に行えるようになりました。コードを見てみましょう。

require 'aws-sdk-core'

ec2 = Aws::EC2::Client.new

begin
  ec2.start_instances(instance_ids: ['i-1234567'])
  ec2.wait_until(:instance_running,  instance_ids:['i-1234567'])
  puts "instance running"
rescue Aws::Waiters::Errors::WaiterFailed => error
  puts "failed waiting for instance running: #{error.message}"
end

start-instancesを実行した後、7行目のwait_untilの部分でステータスのポーリングを実施し、ステータスがinstance_runningになるまで監視してくれます。ただし、一定期間内にステータスが想定のステータスにならなかった場合、例外となります。
以下のように記述することで、監視のインターバルや最大リトライ数を調整することもできます。

require 'aws-sdk-core'

ec2 = Aws::EC2::Client.new

begin
  ec2.start_instances(instance_ids: ['i-1234567'])
  ec2.wait_until(:instance_running,  instance_ids:['i-1234567']) do |waiter|
    waiter.interval     = 5 # number of seconds to sleep between attempts
    waiter.max_attempts = 1 # maximum number of polling attempts
  end
  puts "instance running"
rescue Aws::Waiters::Errors::WaiterFailed => error
  puts "failed waiting for instance running: #{error.message}"
end

対話型コンソール

SDK v2のgemに付随して、aws.rbというコマンドもついてきます。これはirbやpryといった対話型コンソールで、手元で簡単にSDKの動きを確認したい時に使えます。
...と思ったら、SDK v1にもaws-rbというのがありました。(このブログを書いていて初めて知りました。。。)

SDK v1との相違点

SDK v2のREADMEにも記載されていますが、セマンティックバージョニングを採用しているので、メジャーバージョンアップには互換性のない変更も含まれます。
上のコードを見ていて気づかれた方もいるかと思いますが、SDK v1とv2では名前空間が異なります。SDK v1ではAWSモジュールに含まれていましたが、SDK v2ではAwsモジュールとなります。大文字小文字に注意しましょう。

また、SDK v1で利用していたAPIの高度なラッパークラスであるResourceクラス(AWS::EC2::Instances等)は、SDK v2の2014/09/26時点ではexperimentalとされています。さらに、aws-sdk-resourcesという別のGemに切り出されたようなので、利用する際には十分に注意しましょう。追加でインストールする場合には、gemコマンドを使ってインストールします。

$ gem install aws-sdk-resources

まとめ

Githubの履歴を見ていたら、SDK v2のrc1がリリースされたのが昨年の11月ということで、最初のrcから1年弱が経過して、ようやく正式版リリースとなりました。まだまだ開発途中の機能もあるようですが、興味のある方は使ってみてはいかがでしょうか。

参考資料