
Durable FunctionsでSlackを使った承認ステップを実装してみた
はじめに
先日AWS Lambda Durable Functionsが発表されました。これにより、複数の手順が必要なアプリケーションやAIワークフローをLambda関数の中だけで簡単に構築できます。
本機能の全体像は以下の記事が参考になります。
マルチステップでフローを定義して実行が可能で、人間による承認などの外部イベントの結果を待機するために使用できるコールバックを作成することができます。
こちらの記事でPythonと、AWSマネジメントコンソール経由でこの承認ステップを承認/拒否する例が載っています。
今回はこちらをTypeScriptとSlackを利用して実装してみます。
概要
登場するLambdaは以下の2つです
- Durable Function(承認などのマルチステップを管理するLambda)
- Slack Webhookを処理するLambda

動作している感じは以下の通りです。

Slackのメッセージから承認と却下の2つのパターンを行っています。Slackのメッセージのボタンを押した瞬間に右側のLambdaの実行が完了しているのが見えると思います。これはDurable Lambdaがcallbackを返し、その結果をSlack→Slack Webhookを処理するLambdaが呼ばれ、そこからDurable Executionのコールバックを完了させることで、待機中だったDurable Lambdaのワークフローが再開し正常終了しているためです。
処理概要を箇条で書きます。
-
- Durable Functionの処理
- 1.1. order_idを受け取る
- 1.2. order_idバリデーションをする
- 1.3. callback_idの発行
- 1.4. callback_idを埋め込んだ承認/却下メッセージをSlackへ送信
- 1.5. Durable Functionは待機状態へ
-
- Slackにて人が承認
- 2.1. (1.4の結果)承認/拒否ボタンが置いてあるInteractiveなメッセージが送信されているので、人間が手動で押下
-
- Lambda(標準, Slack Webhook を処理する関数URLサーバー)
- 3.1. 項2.1.の結果を受け取り、Durableのcallback_idに対して結果を送信
-
- 項3.1.によりDurable Functionが再開
- 4.1.a. 却下の場合、Slackへ却下通知
- 4.1.b. 承認の場合、注文処理を実施して、Slackへ承認通知
ソースコードはこちらのリポジトリに置いています。
以下順で構築していきます。
- 承認等マルチステップを実行するLambda(Durable Function)
- Slack Webhookを処理するLambda
- Slack App
構築
承認等マルチステップを実行するLambda(Durable Function)の構築
上記のリポジトリを利用する想定で説明します。
pnpm install
# Durable Functionが利用可能なオハイオリージョンを選択
export AWS_REGION=us-east-2
# AWSアカウントIDを設定
export ACCOUNT_ID="<YOUR AWS ACCOUNT_ID>"
# AWS資格情報を取得
IAMロールの作成
aws iam create-role \
--role-name "durable-function-role" \
--assume-role-policy-document "file://lambda/durable/trust-policy.json"
AWSLambdaBasicExecutionRoleのアタッチ
aws iam attach-role-policy \
--role-name "durable-function-role" \
--policy-arn "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
チェックポイント用ポリシーの作成
# テンプレートからポリシーファイルを生成
perl -pe "s/REGION/us-east-2/g; s/ACCOUNT_ID/${ACCOUNT_ID}/g" \
lambda/durable/checkpoint-policy-template.json > lambda/durable/checkpoint-policy.json
# ポリシーを作成
aws iam create-policy \
--policy-name "durable-checkpoint-policy" \
--policy-document "file://lambda/durable/checkpoint-policy.json"
# ポリシーをアタッチ
aws iam attach-role-policy \
--role-name "durable-function-role" \
--policy-arn "arn:aws:iam::${ACCOUNT_ID}:policy/durable-checkpoint-policy"
S3バケットの作成
aws s3 mb "s3://my-lambda-deploy-bucket-${ACCOUNT_ID}"
Lambda関数の作成(初回ビルド・デプロイ含む)
cd lambda/durable
# ビルド(依存関係も含めてバンドル)& zipにまとめる
pnpm build && zip function.zip dist/index.mjs
# S3にアップロード
aws s3 cp function.zip "s3://my-lambda-deploy-bucket-${ACCOUNT_ID}/"
# Lambda関数を作成
aws lambda create-function \
--function-name "myDurableFunction" \
--runtime "nodejs24.x" \
--role "arn:aws:iam::${ACCOUNT_ID}:role/durable-function-role" \
--handler "dist/index.handler" \
--code "S3Bucket=my-lambda-deploy-bucket-${ACCOUNT_ID},S3Key=function.zip" \
--durable-config '{"ExecutionTimeout": 900, "RetentionPeriodInDays":1}'
これでデプロイは完了です。オハイオリージョンのLambda一覧にタイプ=永続で作成されていることが確認できます。まだSlackのトークンを環境変数に入れていないのでエラーになります。この後の手順で更新します。

中のコードについて解説します。基本的にはコメント通りですが、注意点を補足します。
本処理でcallbackの結果を待機します。
Slackで却下をしたら、notify-result でSlackへ却下通知。Slackで承認したら、process-order で 注文処理をして、 notify-result でSlackへ承認通知を行います。
Slack Webhookを処理するLambdaの構築
SlackからのWebhookを処理するHono on Lambda関数URLでpublicに公開しています。サーバー実装は以下の通りです。WebhookのPOSTボディ部にDurable Functionのcallback_idが入っている想定です。
以下がDurable Functionへコールバックに結果を送信している箇所です。
リポジトリのコードを使う場合、以下のコマンドでデプロイできます。
# Durable Functionが利用可能なオハイオリージョンを選択
export AWS_REGION=us-east-2
# AWS資格情報取得
$ cd iac
$ pnpm cdk deploy
$ pnpm cdk deploy
Bundling asset for-durable-lambda-stack/WebhookLambda/Code/Stage...
for-durable-lambda-stack: creating CloudFormation changeset...
(中略)
✅ for-durable-lambda-stack
✨ Deployment time: 61.17s
Outputs:
for-durable-lambda-stack.WebhookUrl = https://dk4mb2fhclsjqlg3mafq73ev6m0eozgv.lambda-url.us-east-2.on.aws/
Stack ARN:
arn:aws:cloudformation:us-east-2:111111111111:stack/for-durable-lambda-stack/03d9a350-cff4-11f0-a106-0af9bed2d1b9
✨ Total time: 62.08s
出力されたURL https://xxxxxxx.lambda-url.us-east-2.on.aws に /webhook/slack をつけた https://xxxxxxx.lambda-url.us-east-2.on.aws/webhook/slack のURLをSlack Appで利用します。
Slack Appの作成
Slack Appを作成します

From scratchを選択

アプリの名前とワークスペースを選択

作成したら以下のような画面遷移します

Interactivity & Shortcutsを選択

Slack Webhookを処理するLambda関数のURL(https://xxxxxxx.lambda-url.us-east-2.on.aws/webhook/slack)をセットします。

Durable FunctionからSlackへメッセージを送信するためのトークンを発行します。

scopeは chat:write のみ付与します。


次に「Install to ワークスペース名」でSlack Appをインストールします。

インストール完了すると、Bot User OAuth Tokenが取得できます。こちらを控えておきます。

Slackに戻るとインストールされていることが確認できます。

Slack Appを入れたら、今回利用するチャンネル #approvals と #approval-results に招待します。


動作確認は以下のコマンドで可能です。
export SLACK_BOT_TOKEN="xoxb-xxx"
curl -X POST https://slack.com/api/chat.postMessage \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${SLACK_BOT_TOKEN}" \
-d '{"channel": "'"#approvals"'","text": "テストメッセージ"}'
承認等マルチステップを実行するLambda(Durable Function)へSLACK_BOT_TOKENを登録
export SLACK_BOT_TOKEN="xoxb-xxx"
aws lambda update-function-configuration \
--function-name "myDurableFunction" \
--environment "Variables={SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN}}"
動かしてみる
冒頭と同じですが、動作している様子は以下の通りです。

Lambdaのテストメッセージに以下を指定し、実行します。
{
"order_id": "order-12345"
}

#approvals チャンネルにメッセージが届きます。承認を押下します。

#approval-results チャンネルに完了が通知されます。


ちなみに却下した結果が以下の通りで、process-orderがないことがわかります。

こちらは処理で外しているためです。
最後に
今回はDurable Functionsのcallback作成機能についてフォーカスしてブログを書きました。生成AIなどと組み合わせてヒューマン・イン・ザ・ループ(HITL)などで活用できそうですね。SDKでTSでワークフローを書けるので静的解析を使ったり、柔軟な表現が可能です。CDKからデプロイできるようになるのが待ち遠しいです。。
TSのSDKのリポジトリを見る限り、Durable Functionsはテストツールや静的解析ツールなどツールチェインもあるようで気になりますね。。時間を見つけてブログを書いていきたいです!
参考
durable-execution-sdkのサンプル集(公式)
SDKの使い方関連







