AWS Step Functionsでタスクタイマーを実装する

2018.03.05

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

AWS Step Functionsを使ったタスクタイマーを10分でプロビジョンするチュートリアルが追加されていたため、実際にやってみました。

ステートマシン

Wait ステートを使って一定時間待機し、Task ステートを使って SNS に通知する Lambda を呼び出します。

最終的には以下のような AWS リソースがプロビジョンされます。

やってみた

以下の手順でサンプルプロジェクトを実行します。

  1. タスクタイマーをプロビジョン
  2. SNS の通知先を設定
  3. 実行
  4. 後片付け

1. タスクタイマーをプロビジョン

Step Function のダッシュボードから ”Create a state machine”を選択します

Sample Projects -> Task Timer を選択し、"Create Sample Project" ボタンをクリックします。

CloudFormation でリソースが作成される旨のメッセージが表示されます。 "Create Resources" ボタンをクリックします。

リソースの作成が始まります。

リソースの作成が完了すると、ステートマシーンを実行する "New execution" のダイアログが表示されます。

Input の JSON において

  • topic はメッセージ送信先 SNS トピック
  • message はトピックに送信するメッセージ
  • timer_seconds は待機する秒数

を表します。

"Start execution" ボタンをクリックして、ステートマシーンを実行します。

ステートマシーンが実行されます。

ログを確認すると ExecutionStarted タイプから WaitStateEntered に遷移し、Input の timer_seconds で指定した秒数だけ待機したあと(WaitStateExited)、Lambda 関数を呼び出している(LambdaFunctionStarted)ことがわかります。

待機時間は WaitStateEnteredWaitStateExited の Elapsed Time(ms) の差分からわかります。

2. SNS の通知先を設定

このステートマシーンの実行が成功すると、 SNS トピックに通知されるのですが、デフォルトではこのトピックには何も購読していていないため、トピックに送信されたメッセージを受け取れません。 Email など確認しやすいプロトコルで購読しましょう。

3. 実行

トピックを追加したところでもう一度ステートマシーンを実行します。 Step Functions の Dashboard から作成されたステートマシーン(TaskTimerStateMachine-XXX のような名前)を選択します。

次に "New execution" ボタンからステートマシンを実行します。

Input には 先程と同じ属性の JSON を指定します。

sample input

{
  "topic": "arn:aws:sns:REGION:123456789012:XXX",
  "message": "HelloWorld",
  "timer_seconds": 10
}

”Start Execution” で実行します。

手順2において、トピックを Email-JSON で購読した場合、以下のようなメールが届きます。

{
  "Type" : "Notification",
  "MessageId" : "xxx",
  "TopicArn" : "arn:aws:sns:ap-northeast-1:123456789012:StepFunctionsSample-TaskTimer-DUMMY",
  "Message" : "task timer sample project",
  "Timestamp" : "2018-03-02T21:46:19.798Z",
  "SignatureVersion" : "1",
  "Signature" : "DUMMY==",
  "SigningCertURL" : "https://DUMMY",
  "UnsubscribeURL" : "https://DUMMY"
}

4. 後片付け

このステートマシーンに関するリソースは全て CloudFormation で作成されています。

CloudFormation のスタック一覧に"StepFunctionsSample-TaskTimer-XXX" のスタック名が存在するため、削除しましょう。

プロビジョン内容を確認

プロビジョニングには CloudFormation を利用しています。 作成されたリソースを確認してみましょう。

作成されたリソース

CloudFormation により以下のリソースが作成されます。

  • Step Functions : TaskTimerStateMachine
  • SNS : SNSTopic
  • Lambda : SendToSNS
  • IAM Role : LambdaExecutionRole
  • IAM Role : StatesExecutionRole

※ 論理ID

Step Functions : TaskTimerStateMachine はメインとなるステートマシーンです。

作成されるステートマシーンの Amazon States Language は以下です。

{
  "Comment": "A Task Timer example of the Amazon States Language scheduling a task",
  "StartAt": "Wait for Timestamp",
  "States": {
    "Wait for Timestamp": {
      "Type": "Wait",
      "SecondsPath": "$.timer_seconds",
      "Next": "Send SNS Message"
    },
    "Send SNS Message": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:1234567890:function:StepFunctionsSample-TaskTimer-XXX",
      "Retry" : [
        {
          "ErrorEquals": [ "States.ALL" ],
          "IntervalSeconds": 1,
          "MaxAttempts": 3,
          "BackoffRate": 2.0
        }
      ],
      "End": true
    }
  }
}

Task ステートで Lambda を呼び出せるように、StatesExecutionRole ロールをアタッチしています。

StatesExecutionPolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

Lambda 関数 SendToSNS は指定された SNS トピックにメッセージ送信するだけのシンプルなものです。 Input から、メッセージ送信先トピックとメッセージを取得しています。

SendToSNS

console.log('Loading function');
const aws = require('aws-sdk');

exports.lambda_handler = (event, context, callback) => {
    const sns = new aws.SNS();
    console.log(`Sending message to SNS topic ${event.topic}`);
    const messageInfo = {
        Message: event.message,
        TopicArn: event.topic       
    };
    sns.publish(messageInfo, (err, data) => {
        if (err) {
            console.error(err.message);
            callback(err.message);
            return;
        }
        console.log(data);
        callback(null);
    });
};

SNS にメッセージ送信できるように、 LambdaExecutionRole ロールをアタッチしています。

LambdaExecutionRole

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "SNS:Publish"
            ],
            "Resource": "arn:aws:sns:ap-northeast-1:123456789012:StepFunctionsSample-TaskTimer-XXX",
            "Effect": "Allow"
        }
    ]
}

最後に

Document History によると、このサンプルプロジェクトは既存のチュートリアルをより試しやすいように CloudFormation 化して 2018/01/18 に追加されたようです。

Step Functions はステートを定義するだけではほぼ何もやれず、タスクなどと連携して初めてまともに動作します。

今回のプロジェクトをサクッと起動すると、あとは Lambda 関数をいじるだけでミニマムなオレオレタスクタイマーの完成です。

参照