ステートマシンの実行ステータスをCloudWatchイベント経由でSlackにメンション通知してみた

先日、Step Functionsにアップデートがあり、ステートマシン実行ステータスの変化でCloudWatchイベントが発行できるようになりました。今回はこちらの機能を利用し、Slackにステートマシンの実行ステータスを通知してみたいと思います。
2019.05.14

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

こんにちは、坂巻です。

先日、Step Functionsにアップデートがあり、ステートマシンの実行ステータスが変化したときにCloudWatchイベントが発行できるようになりました。

[アップデート]Step Functionsの実行ステータスが変化したときにCloudWatchイベントが発行できるようになりました!

今回はこちらの機能を利用し、Slackにステートマシンの実行ステータスを通知してみたいと思います。

目次

  • 構成図
  • Slack Webhook設定
  • Lambda関数作成
  • ステートマシン作成
  • CloudWatchイベントルール作成
  • 動作確認

構成

ステートマシンのステータスが変化した際に、CloudWatchイベントを発行し、CloudWatchイベントルールにてLambda関数を起動させます。

00

Slack Webhook設定

Slackワークスペースに「Incoming WebHooks」アプリを追加します。以下、URLにアクセスします。

  • https://ワークスペース名.slack.com/apps

上記URLのワークスペース名は適宜読み替えてください。

検索より「Incoming WebHooks」を入力し、結果に表示された「Incoming WebHooks」をクリックします。

01

「設定を追加」クリックします。

02

通知先のチャンネルを指定し「Incoming Webhook インテグレーションの追加」をクリックします。

03

WebHookのURLが表示されますので、このURLを控えておきます。(後ほどLambda関数で使用します。)

04

Lambda関数作成

CloudWatchイベントルールで起動させるLambda関数と、ステートマシンから起動させるLambda関数を作成します。

LambdaToSlack

CloudWatchイベントルールで起動させるLambda関数を作成します。

ここでは、メンション先(SlackメンバーID)を入力イベントで受けとるようにしました。ステータスがSucceeded以外の場合、outputフィールドはNULLになりますので、ステータスを判定してSucceededの場合は、ステートマシン(Lambda)が生成した値を通知し、Succeeded以外の場合は、ステートマシンの実行ARNをメッセージとします。

先程控えた、SlackのWebhook URLは、環境変数に設定します。

05

Lambda関数のコードは以下となります。

import json
import os
from urllib.request import Request, urlopen
 
def lambda_handler(event, context):
    #環境変数よりWebHook URL取得   
    hook_url = os.environ['HOOK_URL']
    #ステートマシンのステータス取得 
    sf_status = event['detail']['status']
    #ステートマシン実行ARN取得
    sf_exec_arn = event['detail']['executionArn']
    #inputイベントは文字列型のため辞書型に変換
    input_event = json.loads(event['detail']['input'])
    #SlackメンバーID取得
    slack_user_id = input_event['SlackUserId']

    #ステータス判定
    if sf_status == "SUCCEEDED":
        #outputイベントは文字列型のため辞書型に変換
        output_event = json.loads(event['detail']['output'])
        #メッセージを取得(ステートマシンにて実行されるLambdaで生成)
        sf_result = output_event['result']
        #メッセージ整形
        message = "status : " + sf_status + "\n" + "result : " + sf_result
    else:
        #メッセージ整形
        message = "status : " + sf_status + "\n" + "result : " + sf_exec_arn

    #SlackメンバーIDをメンション形式に整形
    mention = "<@" + slack_user_id + ">"

    slack_message = {
        'text': mention + "\n" + message,
        # メンション有効
        'link_names': 1 
    }

    req = Request(
        hook_url, 
        json.dumps(slack_message).encode('utf-8'),
        )
    #リクエスト
    response = urlopen(req)
    response.read()

Function1

ステートマシンから起動させるLambda関数を作成します。実行時に渡すイベントで、戻り値を変えています。

def lambda_handler(event, context):
    flg = event['Function1']

    if flg == "Success":
        ret_msg = "Function1 Success"
    else:
        ret_msg = "Function1 Fail"
    return ret_msg

Function2

ステートマシンから起動させるLambda関数を作成します。実行時に渡すイベントで、戻り値を変えています。

def lambda_handler(event, context):
    flg = event['Function2']

    if flg == "Success":
        ret_msg = "Function2 Success"
    else:
        ret_msg = "Function2 Fail"
    return ret_msg

ステートマシン作成

Lambda関数を実行するステートマシンを作成しました。呼び出されたLambda関数は戻り値を返すようにしているので、Choiceにて戻り値を判定し、ステートを分岐させています。また、ResultPathを使用して入力イベントの一部を置き換えています。

06

ステートマシンの定義は以下となります。

{
  "StartAt": "Functions1",
  "States": {
    "Functions1": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:Function1",
      "ResultPath": "$.result",
      "Next": "Functions1 Success ?"
    },
    "Functions1 Success ?": {
      "Type": "Choice",
      "Choices": [{
        "Variable": "$.result",
        "StringEquals": "Function1 Success",
        "Next": "Functions2"
      }],
      "Default": "EndFail"
    },
    "Functions2": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:Function2",
      "ResultPath": "$.result",
      "Next": "Functions2 Success ?"
    },
    "Functions2 Success ?": {
      "Type": "Choice",
      "Choices": [{
        "Variable": "$.result",
        "StringEquals": "Function2 Success",
        "Next": "EndSuccess"
      }],
      "Default": "EndFail"
    },
    "EndFail": {
      "Type": "Fail"
    },
    "EndSuccess": {
      "Type": "Succeed"
    }
  }
}

CloudWatchイベントルール作成

ステートマシンが発行するCloudWatchイベントにて、Lambda関数を起動させるルールを作成します。

先程作成したステートマシンのARNを指定し、ここではSUCCEEDEDと、FAILEDステータスを設定しました。ターゲットには先程作成したLambda関数「LambdaToSlack」を指定します。

07

動作確認

成功時

SUCCEEDEDステータスの動作を確認します。以下のイベントを渡しステートマシンを実行します。

{
  "Function1": "Success",
  "Function2": "Success",
  "SlackUserId": "UA7TVTSD6"
}

「EndSuccess」ステートが実行され、ステータスが「成功」になりました。

08

14

指定したSlackユーザに、Lambda関数(Functions2)が生成した値「Function2 Success」が通知されました。

09

失敗時

Function1エラー

FAILEDステータスの動作を確認します。以下のイベントを渡しステートマシンを実行します。

{
  "Function1": "Fail",
  "Function2": "Success",
  "SlackUserId": "UA7TVTSD6"
}

「EndFail」ステートが実行され、ステータスが「失敗」になりました。

10 15

指定したSlackユーザに、ステートマシンの実行ARNが通知されました。

11

Function2エラー

FAILEDステータスの動作を確認します。以下のイベントを渡しステートマシンを実行します。

{
  "Function1": "Success",
  "Function2": "Fail",
  "SlackUserId": "UA7TVTSD6"
}

「EndFail」ステートが実行され、ステータスが「失敗」になりました。

12 16

指定したSlackユーザに、ステートマシンの実行ARNが通知されました。

13

さいごに

これまでステートマシン内で生成した値を通知しようとなると、つくりこみが必要でしたが、今回のアップデートで簡単に通知できるようになりましたね!!

参考