[StepFunctions]実行中のステートマシン内から実行ARN、もしくは実行名を取得したかった話
はじめに
前回に引き続き、GitHub Copilotに聞いて解決した問題になります。
よろしければ、前回の記事も合わせてご覧ください。
やりたいこと
今回も記事のタイトル通りですが、、、
実行中のStepFunctionsの実行ARN(executionArn
)、もしくは実行名(name
)を取得しようとしました。
背景
やりたいことの背景としては、既存運用では以下の対応(後述のGitHub Copilot提案の方法2のパターン)をしていました。
しかし、StepFucntionsを実行時に手動で引数を埋めるという運用が一手間かかったため、改善できないか調べていました。
- StepFunctionsの実行時の引数に、実行名を手動で入力して取得
- 同StepFucntionsから呼び出されるLambdaに対して、手動入力した実行名を引数に渡して実行
- Lambdaのロジック内で、実行名を元にAWSアカウントID等を付け加えて、実行ARNを生成
- 実行ARNを元に、実行しているStepFucntionsのURLを生成
- 生成したURLを含んだSlack通知を実施
LambdaからSlack通知の実装については、難しいことはしていないため、本記事では割愛します。
参考までに、非常に分かりやすいハンズオンを公開していた mn87 様の記事を貼り付けておきます。
事前に確認したポイント
独自実装等はせずに、用意されているStepFucntionsのアクションでやりたいことが実現できないか確認しました。
しかし、アクションで渡せる引数がstateMachineArn
程度しか無く、現状では実行中のARNを取得する方法は見つかりませんでした。
GitHub Copilotに聞いてみた
そこで、前回記事同様に、GitHub Copilot Chatに聞いてみました。
imamura-ko-0314
AWS StepFunctionsにて、実行中のステートマシン内から、その実行中のexecutionArn
を取得する方法はありますか?
GitHub Copilot
AWS Step Functionsでは、実行中のステートマシン内から直接executionArn
を取得するためのネイティブな方法は提供されていません。
しかし、いくつかの方法で間接的にexecutionArn
を取得することが可能です。方法1: Lambda関数を使用する
AWS Lambda関数を使用して、context
オブジェクトからexecutionArn
を取得し、それをステートマシンに返す方法があります。Lambda関数の例
import json def lambda_handler(event, context): execution_arn = context.invoked_function_arn return { 'executionArn': execution_arn, 'input': event }
Step Functionsの定義例
{ "Comment": "A description of my state machine", "StartAt": "GetExecutionArn", "States": { "GetExecutionArn": { "Type": "Task", "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_LAMBDA_FUNCTION", "End": true } } }
方法2: ステートマシンの入力に含める
ステートマシンを開始する際に、executionArn
を入力パラメータとして含めることもできます。
これにより、ステートマシン内の各ステートでexecutionArn
にアクセスできます。ステートマシンの開始例
aws stepfunctions start-execution \ --state-machine-arn arn:aws:states:REGION:ACCOUNT_ID:stateMachine:YOUR_STATE_MACHINE \ --input '{"executionArn": "arn:aws:states:REGION:ACCOUNT_ID:execution:YOUR_STATE_MACHINE:EXECUTION_NAME"}'
Step Functionsの定義例
{ "Comment": "A description of my state machine", "StartAt": "YourFirstState", "States": { "YourFirstState": { "Type": "Pass", "ResultPath": "$.executionArn", "Next": "NextState" }, "NextState": { "Type": "Task", "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:YOUR_LAMBDA_FUNCTION", "End": true } } }
これらの方法を使用することで、実行中のステートマシン内から
executionArn
を取得し、必要な処理を行うことができます。
やはり、実行中のStepFunctions内から直接executionArn
を取得するための方法はないようでした。
そして、代替案として提案された方法2は、既存の運用ままのものでした。
ただし方法1については、やりたいことの背景にも記載した通り、LambdaでSlack通知する中でexecutionArn
が欲しかったので、要望と合致する上に手間が減るようなBestPracticeのようでした!!
実際に動かしてみた
Lambdaのcontextオブジェクトを活用するように、Slack通知用のLambdaを実装しました。
以下のようなサンプルコードで、意図通りに値が取得できることが確認できました!
import json
import urllib.request
import os
WEBHOOK_URL = 'SLACK_WEBHOOK_URL_XXXX'
CHANNEL_NAME = 'SLACK_CHANNEL_NAME_XXXX'
def post_slack(param, context):
execution_arn = context.invoked_function_arn
webhook_url = WEBHOOK_URL
channel = CHANNEL_NAME
env_name = os.getenv('ENV_NAME')
payload = get_payload(param, env_name, channel, execution_arn)
data = json.dumps(payload).encode('utf-8')
method = 'POST'
headers = {'Content-Type': 'application/json'}
request = urllib.request.Request(webhook_url, data = data, method = method, headers = headers)
with urllib.request.urlopen(request) as response:
return response.read().decode('utf-8')
def get_payload(param, env_name, channel, execution_arn):
subject = 'ERROR: '
message = 'Environment: {}'.format(env_name)
if 'states' in execution_arn:
# 本LambdaがStepFunctionsからの実行だった場合
sf_task_url = 'https://ap-northeast-1.console.aws.amazon.com/states/home?region=ap-northeast-1#/v2/executions/details/{}'.format(execution_arn)
message = message + '\nSF Execution Link: {}'.format(sf_task_url)
payload = {
'attachments':[{
'fields':[
{
'title': subject,
'value': message
}
]
}],
'channel': channel
}
return payload
def lambda_handler(event, context):
post_slack(event, context)
まとめ
反省点として、、、
どうしても1人の頭で考えていると、挙動の改善をするためにStepFunctions側の挙動にこだわってしまっていて、凝り固まった考えになっていました。
やりたいことを実現するために、別のソリューションも提案してくれるGitHub Copilot最高!!
また、最後に今回活用したPythonのLambda contextオブジェクトについてのリファレンスがあったため、こちらを貼り付けておきます。
Discussion