Glacierのジョブの完了をPythonからじっと待つ
長いタイトルで意味もよく分かりませんが。
○ 何がやりたいの
Amazon Glacierのダウンロードにはまず「準備」に約4時間かかるそうで、これは同期処理にはなっていない。Amazon SNS経由で「ダウンロードの準備が出来たよ」という通知を、emailやhttp、Amazon SQS経由で受け取れる。非常にゆったりしたテンポで良いのであれば、emailを見た後にダウンロードを開始すればOK。
今回はそれを同期的に処理してみたい。具体的には、コマンドラインでGlacierからの通知をポーリングして、準備できた段階ですぐにダウソする。ついでなのでそれをPythonのbotoでやる。
というわけでAWSほとんど触れてない私がそのあたりをやってみた
注1: 約4時間ということは分かっているので、急がなければ5時間程度スリープするだけでも良い。確実に完了するというお墨付きはないんだけど。
注2: 今回の方法はコマンドラインで一発、を目指している。もしもっと複雑で良いのであればhttpリクエストから起動するコールバック的な仕組みを実装しても良いし、メンテ出来るのならそちらのほうが筋。今回のスクリプトは通知が来てから最大1分程度起動に時間がかかる (プッシュ通知によるものではなくあくまでポーリング)
注3: Javaや.NETでは公式のライブラリがあるようなので、そちらだともっと楽に出来るはず。
○ 大まかな流れ
Amazon側は Amazon Glacier -> Amazon SNS (Simple Notification Service) -> Amazon SQS (Simple Queue Service) という3つのサービスを繋げることで実現できる。ストレージ (Glacier) から、通知フレームワーク (SNS) を経由し、キュー (SQS)に行く。私がやるのは最後のキューのメッセージをポーリングで待つだけ。
少し具体的には、
Appendix C: Sending Amazon SNS Messages to Amazon SQS Queues
今回はそういった作業をプログラムでやる。話を単純化するため、プロダクションでは必要になる可能性が高い各種のエラーハンドリング(排他処理とかキューの共有とか)はとりあえず考えない。
○ 外堀を埋めるためのコマンドライン
上記の処理自体を行うものではないのだけど、glacier-cmd というのを使ってJobとかの状態を監視すると便利。
https://github.com/uskudnik/amazon-glacier-cmd-interface
今回はデバッグ的な用途でお世話になった。具体的にはジョブ状態の手での監視など。
スクリプトから使う方法ももちろんあるのだけど、今回の要求ズバリのコマンドは見当たらなかった。なお、githubでは同様のケースについてのディスカッションがあったようだ。15日前に。
https://github.com/uskudnik/amazon-glacier-cmd-interface/issues/62
○ Vaultに関係するイベント2種類
「解凍」を要求するイベントには2種類
○ コード
https://github.com/dmiyakawa/glacier_exp_py/blob/6debe43c2efbea070217f560cdff773b3d6740af/wait_for_job_complete.py
SQSのキューとSNSのトピックを勝手に作って対象のVaultのイベントをただ監視する。
コードをまるで整理してないので割と微妙な感じではあるが、まぁやることはやってるはず。ついでにgithubほとんど初めて使った関係で何かひどいことに。gracierとかいうタイポが。
ちなみに、キューにメッセージがあったケースの処理が特に雑なので注意。SQSでは、読んだメッセージが一時的に読めなくなる、的な挙動を抑える必要があるかもしんない。具体的には、多分Default Visibility Timeoutを変更すれば良い。
○ ラフなテスト
実際にGlacierのジョブが終わるのを待つと本気で1イテレーション4時間かかるので、しばらくイベントはAWSのWebコンソールから手で送って試してた。
2つめのテストでハマった。というのも、デフォルトでは自分の作ったSQSに対してもSNSはメッセージを送ってくれないから。Amazonの公式の説明(上と同じリンク)や、以下の記事なども少し参考になる
http://www.elastician.com/2010/04/subscribing-sqs-queue-to-sns-topic.html
○ 本当のGlacierのイベントを取得した時の挙動など
昨日の夜、バグ退治してコマンド打って放置し、今朝見たらメッセージをトラップできていた、という感じ。
○ 感想
総じて、大本となるAWSのモデルは背景事情を理解すれば適切なのでなんとかなる。botoはモジュール毎に多分作者が違っているっぽく、boto.glacier、boto.sns、boto.sqsで書き味が違うのが面倒。自分で書くってなると絶望的なめんどさになるので頼るけど。
自分のコード的には、ARNの作り方がそれで合ってるかとか色々やっぱり危険な臭いがする。
○ 別の考察
本当はコールバックから簡単にバッチ処理が起こせると良いのだけど。
もちろんメールサーバを持っておく、HTTPサーバでフックするなどあるものの、詳細考えると今回のケースだけに準備するのはややオーバーキルだし、げんなりする。メンテしてらんない。
SQSあたりに「ここに接続しておいてねプッシュするからね」みたいな仕組みがあるとすっげー楽かもしれない (そのコネクションをルータとかで切られなければ)。まぁ今の時点で十分楽だけどな。
○ おまけ1
S3スキップしてGlacier扱うってのはやはり本筋じゃないんだろうなぁ
○ おまけ2
Pythonのコードにpassが大量にあるのはemacsのPython modeがそれをブロックの終わりと認識してくれてるからだにょ。endの代わりにょ
○ おまけ3
SNSもSQSも別ユーザから中の様子をチェックしたり操作したりできるが、それをやる場合はさらにポリシーやパーミッションの設定が必要。そこまで行ったら多分手でSNSとSQSは管理する方が良いかもしれない。
ただ、今回軽く触れた印象でもJSON形式などで流しこめばそういう込み入ったことも外部からプログラム出来るようにはなっているので、不可能ということはない気がする。動的にパーミッションを追加、削除とかやり始めちゃう会社とか、すでにある気がするよ。
○ 他に参考にした記事など
http://blog.psyche.gaso.jp/20120831-1.html
○ 何がやりたいの
Amazon Glacierのダウンロードにはまず「準備」に約4時間かかるそうで、これは同期処理にはなっていない。Amazon SNS経由で「ダウンロードの準備が出来たよ」という通知を、emailやhttp、Amazon SQS経由で受け取れる。非常にゆったりしたテンポで良いのであれば、emailを見た後にダウンロードを開始すればOK。
今回はそれを同期的に処理してみたい。具体的には、コマンドラインでGlacierからの通知をポーリングして、準備できた段階ですぐにダウソする。ついでなのでそれをPythonのbotoでやる。
というわけでAWSほとんど触れてない私がそのあたりをやってみた
注1: 約4時間ということは分かっているので、急がなければ5時間程度スリープするだけでも良い。確実に完了するというお墨付きはないんだけど。
注2: 今回の方法はコマンドラインで一発、を目指している。もしもっと複雑で良いのであればhttpリクエストから起動するコールバック的な仕組みを実装しても良いし、メンテ出来るのならそちらのほうが筋。今回のスクリプトは通知が来てから最大1分程度起動に時間がかかる (プッシュ通知によるものではなくあくまでポーリング)
注3: Javaや.NETでは公式のライブラリがあるようなので、そちらだともっと楽に出来るはず。
○ 大まかな流れ
Amazon側は Amazon Glacier -> Amazon SNS (Simple Notification Service) -> Amazon SQS (Simple Queue Service) という3つのサービスを繋げることで実現できる。ストレージ (Glacier) から、通知フレームワーク (SNS) を経由し、キュー (SQS)に行く。私がやるのは最後のキューのメッセージをポーリングで待つだけ。
少し具体的には、
- SNSとSQSにそれぞれ新しい「トピック」と「キュー」を作る
- キューが「トピック」からの通知を受け取れるようポリシーを設定する
- それらトピックとキューを関連付ける。
- Glacierの「準備できたよ」イベントの通知先をSNSのその「トピック」に振り分ける
- キューを1分おきとかでポーリングして、Vaultの「準備できた」のメッセージがキューに入ったところで起動。1分ブランクがあるのは我慢して。
Appendix C: Sending Amazon SNS Messages to Amazon SQS Queues
今回はそういった作業をプログラムでやる。話を単純化するため、プロダクションでは必要になる可能性が高い各種のエラーハンドリング(排他処理とかキューの共有とか)はとりあえず考えない。
○ 外堀を埋めるためのコマンドライン
上記の処理自体を行うものではないのだけど、glacier-cmd というのを使ってJobとかの状態を監視すると便利。
https://github.com/uskudnik/amazon-glacier-cmd-interface
今回はデバッグ的な用途でお世話になった。具体的にはジョブ状態の手での監視など。
スクリプトから使う方法ももちろんあるのだけど、今回の要求ズバリのコマンドは見当たらなかった。なお、githubでは同様のケースについてのディスカッションがあったようだ。15日前に。
https://github.com/uskudnik/amazon-glacier-cmd-interface/issues/62
○ Vaultに関係するイベント2種類
「解凍」を要求するイベントには2種類
- Archive Retrieval Job Complete アーカイブ準備できたよ
- Vault Inventory Retrieval Job Complete インベントリが準備できたよ
アーカイブ自体をダウンロードする場合は1つめが重要 (今回の私は「Archive IDわすれたー!」という話もあったので2つ目。Archive ID、一度忘れると再入手に約4時間かかります)
○ コード
https://github.com/dmiyakawa/glacier_exp_py/blob/6debe43c2efbea070217f560cdff773b3d6740af/wait_for_job_complete.py
SQSのキューとSNSのトピックを勝手に作って対象のVaultのイベントをただ監視する。
コードをまるで整理してないので割と微妙な感じではあるが、まぁやることはやってるはず。ついでにgithubほとんど初めて使った関係で何かひどいことに。gracierとかいうタイポが。
ちなみに、キューにメッセージがあったケースの処理が特に雑なので注意。SQSでは、読んだメッセージが一時的に読めなくなる、的な挙動を抑える必要があるかもしんない。具体的には、多分Default Visibility Timeoutを変更すれば良い。
The length of time (in seconds) that a message received from a queue will be invisible to other receiving components.これがあると、30秒の間「メッセージがないよ」って言われる。手で変更するのはWebコンソールから。プログラムについては調べてない。
○ ラフなテスト
実際にGlacierのジョブが終わるのを待つと本気で1イテレーション4時間かかるので、しばらくイベントはAWSのWebコンソールから手で送って試してた。
- マニュアルなテスト1: WebコンソールからSQSにメッセージ直接突っ込む
- マニュアルなテスト2: WebコンソールからSNSのトピックにメッセージをpublish
2つめのテストでハマった。というのも、デフォルトでは自分の作ったSQSに対してもSNSはメッセージを送ってくれないから。Amazonの公式の説明(上と同じリンク)や、以下の記事なども少し参考になる
http://www.elastician.com/2010/04/subscribing-sqs-queue-to-sns-topic.html
○ 本当のGlacierのイベントを取得した時の挙動など
> ./wait_for_job_complete.py Backup_20121015_1
Vault: arn:aws:glacier:ap-northeast-1:768551134739:Backup_20121015_1
Queue: arn:aws:sqs:ap-northeast-1:768551134739:wait_for_job_complete_queue
Topic: arn:aws:sns:ap-northeast-1:768551134739:wait_for_job_complete_topic
Waiting for some message from the queue wait_for_job_complete_queue.
New message found: {
"Type" : "Notification",
"MessageId" : "74b90312-8244-461b-a757-930b19ab060f",
"TopicArn" : "arn:aws:sns:ap-northeast-1:768551134739:wait_for_job_complete_topic",
"Message" : "{\"Action\":\"ArchiveRetrieval\",\"ArchiveId\":\"ながーいid\",\"ArchiveSizeInBytes\":501510000,\"Completed\":true,\"CompletionDate\":\"2012-10-17T12:26:03.931Z\",\"CreationDate\":\"2012-10-17T08:25:54.838Z\",\"InventorySizeInBytes\":null,\"JobDescription\":null,\"JobId\":\"ながーいid\",\"SHA256TreeHash\":\"はっしゅ\",\"SNSTopic\":null,\"StatusCode\":\"Succeeded\",\"StatusMessage\":\"Succeeded\",\"VaultARN\":\"arn:aws:glacier:ap-northeast-1:(user id):vaults/BackupTestNyo\"}",
"Timestamp" : "2012-10-17T12:26:04.058Z",
"SignatureVersion" : "1",
"Signature" : "しぐねちゃー",
"SigningCertURL" : "https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-なにか.pem",
"UnsubscribeURL" : "https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:(user id):wait_for_job_complete_topic:なにか"
}
Waited for 142.726362 min.
Now: 2012-10-17 21:04
昨日の夜、バグ退治してコマンド打って放置し、今朝見たらメッセージをトラップできていた、という感じ。
○ 感想
総じて、大本となるAWSのモデルは背景事情を理解すれば適切なのでなんとかなる。botoはモジュール毎に多分作者が違っているっぽく、boto.glacier、boto.sns、boto.sqsで書き味が違うのが面倒。自分で書くってなると絶望的なめんどさになるので頼るけど。
自分のコード的には、ARNの作り方がそれで合ってるかとか色々やっぱり危険な臭いがする。
○ 別の考察
本当はコールバックから簡単にバッチ処理が起こせると良いのだけど。
もちろんメールサーバを持っておく、HTTPサーバでフックするなどあるものの、詳細考えると今回のケースだけに準備するのはややオーバーキルだし、げんなりする。メンテしてらんない。
SQSあたりに「ここに接続しておいてねプッシュするからね」みたいな仕組みがあるとすっげー楽かもしれない (そのコネクションをルータとかで切られなければ)。まぁ今の時点で十分楽だけどな。
○ おまけ1
S3スキップしてGlacier扱うってのはやはり本筋じゃないんだろうなぁ
○ おまけ2
Pythonのコードにpassが大量にあるのはemacsのPython modeがそれをブロックの終わりと認識してくれてるからだにょ。endの代わりにょ
○ おまけ3
SNSもSQSも別ユーザから中の様子をチェックしたり操作したりできるが、それをやる場合はさらにポリシーやパーミッションの設定が必要。そこまで行ったら多分手でSNSとSQSは管理する方が良いかもしれない。
ただ、今回軽く触れた印象でもJSON形式などで流しこめばそういう込み入ったことも外部からプログラム出来るようにはなっているので、不可能ということはない気がする。動的にパーミッションを追加、削除とかやり始めちゃう会社とか、すでにある気がするよ。
○ 他に参考にした記事など
http://blog.psyche.gaso.jp/20120831-1.html