MyCSS

2012/03/15

Amazon SWFつかってみた(ながいよ) はてなブックマークに追加

それは突然にやってきた
AWS界隈ではDynamoDB祭りが開かれているまっただ中の2012年02月22日、いつものように何の前触れも無く、こっそりとManagement Consoleにタブが追加されました。Twitterで「何このタブは?」という情報が拡散してから公式ブログに発表になるという、最近おなじみのパターンですw
SWF?なにAWSでFlashが出来るの?などと一瞬思いましたが、もちろんそんなわけは無く、Simple Workflow Serviceの略でSWS、もとい、SWFでした。あれっw?

ワークフローと聞いて
自分が一番最初にイメージするのは、経費や稟議の申請処理なんかを思いつきますが、Amazon SWFはすでにNASAでも使われていると言う事で、火星への交通費の精算に使われたり、探査機が撮った膨大な写真を処理するのに使われているようです。 (一応言っておくと、前者は冗談です。)
SWFとはなんぞや?と言う事は、他でもイロイロ言われていると思いますので、詳細は割愛させて頂きます(汗)
※と言いつつ、現状AWSの公式ドキュメントくらいしか無いような気がする。

AWS Flow Framework
今回のJava SDKは気合いが入っています。DynamoDBの時もシャレオツなDataMapperがSDKに入っていて「おぉ!」と思ったけれども、SWFの場合はフレームワークが入っていて若干のけぞりました。その名もAWS Flow Frameworkです。

どれどれ、と思ってサンプルコードをダウンロードして手元のEclipseに取り込んだら、いきなりコンパイルできない。理由が、あるべきクラスが無いと言うもの。「これ、きっと中の人が入れ忘れたんじゃね(苦笑)?」などと思って調べてみたら、なんとAPT(Annotation Processing Tool)でクライアントコードが自動生成される事が判明。正直ビビりました(笑)

理解するまで結構時間かかりました(汗)
SWFはその他のAWSサービスと違って、結構複雑です。いや、API自体はシンプルなのは間違いないです。けれども、そもそもワークフローを扱うのですから、それなりに面倒な事になります。
※でも、そういうマンドクサイものを汎用的なAPIを仕立ててくるAWSはさすがです…。

まぁ、そうとはいえ、Flow Frameworkを使えばかなりスッキリしたコードが書ける事が分かりました。ただし、非同期な動きを良く理解しないと、振る舞いが意味不明な感じになります。java.util.concurrent.Future<V>を使ったプログラムを書いた事があれば、結構すんなり受け入れられるかな?とは思います。

そして、出来る事は沢山あります。自分もまだ全貌を把握しきれていません。とりあえず、最初の一発目を動かすのに結構苦労したので、自分がやってみた事を記事にしておきます。

間違い等あれば、ご指摘ください!!

サンプルワークフロー
実際に試すにあたり、こんなワークフローを考えてみました。
  1. だれかがS3へ画像をアップロードする
  2. S3から画像をダウンロードする
  3. モノクロに変換する
  4. 処理完了をメールでお知らせする
まぁ、AWSが提供しているサンプルに激しく近い感じですが、サンプルに適したよい例が思いつかなかったのでご了承くださいw

やったこと

1.まずはSWFドメインを作成する

ドメインが無い事には始まりませんので、Management Consoleから作成します。
Create a new Domainをクリックします。

以下のように設定します。Nameは何でもよいですが、プログラムから参照しますので分かりやすいものがよいでしょう。また、現状では一度登録したドメインが消せないようなので、注意が必要です。(Deprecate(廃止)する事は可能です)



2.SNSにトピックを作成する

今回はメール通知用にAmazon SNSを使う事にします。今回は新たに専用のトピックを作成してみます。Management ConsoleのSNSのタブに移動して、Create New Topicボタンをクリックします。
Topic Nameを入力。Display Nameは日本語が入らないんだなー。
 トピックが出来たら、メールの通知先を加えましょう。Create New Subscriptionをクリック。
 ProtocolにEmailを選択し、メールアドレスを入力。
Subscribeすると、AWSから確認メールが送られて来るので、Confirm subscriptionのURLをブラウザで開きます。
こんな感じで表示されればOKです。 
なお、TopicARNはプログラムから参照する必要があるので控えておきましょう。

3.Eclipseでプロジェクトを作る

Flow Frameworkを使う際、APTを使う設定をしないとどうにもなりませんので、ここはしっかりやる必要があります。

始めはMavenベースでやろうと思ったけど、aws-java-sdk-flow-build-tools.jarがリポジトリに見当たらなかったので、ここは素直にAWS Toolkit for Eclipseを使う事にしました。

Build PathにAWS SDK for Javaが入っている事を確認しましょう。


重要なのが、Annotation ProcessingがEnableになっている事です。

Eclipseのデフォルトでは.apt_generatedというディレクトリに生成されますが、自分の好きなものを指定してもよいかもしれません。ただ、srcには入れない方がよいでしょう。

4.Activityを定義する

ふぅ。ようやく本題に入る事が出来そうです(笑)

最初はワークフロー実行に必要なActivityを定義します。必要なものは以下です。
  • S3へのアップロード
  • S3からのダウンロード
  • 画像モノクロ変換
  • メール通知
ActivityはInterfaceとして定義して、@Activitiesアノテーションを加えるのが決まりです。こんな感じのソースを書きました。


5.Workflowを定義する

WorkflowもInterfaceとして定義して、@Workflowアノテーションを加えます。


6.Activityを実装する

実装の中身はそれほど重要じゃないと思うので、ここでは割愛しますね。コードはgithubに置いてありますので、ご興味あればどーぞ。


7.Workflowを実装する

Workflowの実装は独特なものがあります。実装コードはこんな感じです。



いきなりS3ActivitiesClientなどというクラスが出てきますが、これらはFlow Frameworkが自動生成したクラスになります。Workflowの実装はこのクライアントを利用するのがキモです。

このクライアントは、アクティビティで定義したメソッドにPromiseでラップした引数を加えたバージョンが多数追加されています。このPromiseですが、詳細な説明はAWSのドキュメントに譲るとして(今回はそんなのばっかりだなぁw)、ざっくり言うとメソッドの実行が非同期で行われ、結果を待たずして次のコードに移るというものです。コードは同期的に見えますが、実際は非同期な振る舞いをします。


8.ActivityWorker、WorkflowWorkerを実装する

さて、ActivityとWorkflowの準備ができましたので、これらを実際にホストするプログラムを書く必要があります。Flow Frameworkでは、ActivityWorker、WorkflowWorkerというものが用意されていますので、これらを素直に使いましょう。


それぞれ引数にドメイン名とタスクリスト名を渡しますが、ドメイン名は先ほどManagement Consoleで作ったドメイン名にします。このコードでは単にworker.start()してるだけですが、きちんと実装する際は不正な形で終了しないようにshutdownHookを引っ掛けてください。

現状のタイミングでActivityを実行するのかどうかを判断するのはWorkflowWorkerです。AWSの言う所のDeciderでしょうか?絵にするとこういうイメージかなぁ?
つ、伝わるかなぁ…っていうか、そもそもあってるかなぁ(汗)

9.ワークフローを実行するコードを書く

ようやくここまで来ました。な、長かった。こんな感じになります。


ここでもFlow Frameworkが自動生成してくれるWorkFlowExternalを使います。

10.実行してみる!

これで準備が整ったので、いざ実行してみましょう。
これには順番が大事です。初回は「8.ActivityWorker、WorkflowWorkerを実装する」で作ったActivityWorkerとWorkflowWorkerを実行します。実は、このWorkerは、ActivityとWorkflowの登録をSWFに対して自動でやってくれるんです。いちいちManagement Consoleで手動で登録する必要がありません。便利ですよ。

Workerを実行後にManagement Consoleで確認すると、ちゃんと登録されているのが分かります。

これでようやくワークフローを実行する事が出来ます。上記のWorkerを実行した状態で、「9.ワークフローを実行するコードを書く」で実装したStarter.javaを実行します。以下のようなログが起動済みの「ActivityHost」から吐き出されたら成功です!

Management Consoleで確認してみましょう。Workflow Executionsをクリックして、Execution StatusをClosedで指定します。

ちゃんとありました!
Workflow Execution IDをクリックすると、実行の履歴を見る事が出来ます。分かりやすい所で、Activityを見てみるとこんな感じです。ちゃんとワークフローが実行されているのが確認できます。


Management Consoleからは、Executionに対して「Signal」「Try-Cancel」「Terminate」「Re-Run」の操作をする事が可能です。分かりやすい所で「Re-Run」してみましょう。

すると、Execution Listに同じWorkflow Execution IDでRun ID違いのExecutionが追加されている事が分かります。ステータスはActiveです。


手元で起動しているWorkerが反応します。ActivityHostからは先ほど同じようなログが出ているのが確認できます。Management Consoleから手元のプログラムが動く感覚は、理屈は分かるとはいえ、実にミョ〜な感じですww


ワークフローが完了すると、ちゃんとCompletedになっている事が確認できます。


まとめ
というわけで、基本的な部分だけつまみ食いした感じですが、おおよその感じがつかんで頂ければ幸いです。

そして見て分かる通り、実際のアクティビティを実行するワーカーはクラウドだろうがオンプレだろうがモバイルだろうがどこにあっても良い、というのがキモだと思います。また、きちんと作れば容易にスケールする事も分かります。

AWSで非同期処理ならばSQSというのが定番ですが、二重処理を防ぐためにメッセージのステート管理を自前でやる必要があったり、SQSにポーリングするプログラムを別途仕込む必要があったりしましたが、こういった事はSWFを使うと一挙に解決されます。

DynamoDBは、SimpleDBで出来なかった事が増えてバンザイな感じでしたけども、SWFもSQSでちょっと面倒だった事が簡単にできるようになった気がします。


続くエントリはこちら:Amazon SWF Flow Frameworkのエラー処理について