今更ながらDurable Functions入門してみる

投稿日:

こんにちは。まーやです。
この投稿は PyLadies Japan Advent Calendar 2021 の6日目の投稿です。
やろうやろうと思って全然自分で動かしたことなかったDurable Functions for Pythonのチュートリアルを PyLadies Tokyo 秋合宿2021 でやってきたので書き残しておこうと思います。

Durable Functions ってなぁに

サーバーレス コンピューティング環境でステートフル関数を記述できる Azure Functions の拡張機能です。

https://docs.microsoft.com/ja-jp/azure/azure-functions/durable/durable-functions-overview?tabs=csharp

と書かれてるんですが、つまりはですね、ステートレス(=前後の処理のステータスに依存しない/持っていない、I/Oだけが単純にお約束として決められている処理)を鉄則として設計・利用する Azure Functionsをステートフル(=前後の状態を保持する処理)な関数ワークフローとして制御できるフレームワーク的なものです。

現在はC#, F#, Power Shell, JavaScript, そしてわれらがPython、で利用可能です。

Durable Functionsが利用できるケースについては↑のページにがっつり書かれているので省略します。個人的に使えるパターンだな、と認識しているのはパターン#2のファンアウト・ファンインとパターン#3の非同期APIですね。

早速チュートリアルしてみます

公式のMS DocsにPython × VSCodeのチュートリアルがありましたので、こちらのチュートリアルをPython × PyCharmでやってみました、というのが今回の本題です。ちなみに、私もこのドキュメントを呼んでなんとなく作業してなんとなく理解しただけなので、間違っているところがあればご指摘お待ちしております・・・・
https://docs.microsoft.com/ja-jp/azure/azure-functions/durable/quickstart-python-vscode

私の理解が正しければ、このチュートリアルは#1の利用パターンである関数チェーンのチュートリアルです。

関数チェーン パターンの図
https://docs.microsoft.com/ja-jp/azure/azure-functions/durable/durable-functions-overview?tabs=python#pattern-1-function-chaining

Durable Functionsには3つの機能を持っテンプレートが用意されています。この3つを組み合わせることで1連のステートフルなワークフローを構築できるというわけです。

  • スターター(クライアント関数)
    • トリガー・オーケストレータなどの設定をする。
    • 今回のチュートリアル的にはF1相当
  • アクティビティ
    • ピュアなロジック関数
    • 呼ばれたタイミングで実行させたいロジックコード
    • 今回のチュートリアル的にはF2/F3/F4にあたります(3回同じアクティビティを呼んでいる)
  • オーケストレーター
    • オーケストレーター。そのまんま。アクティビティをどんなふうに呼びたいのか、何回呼びたいのかなどを制御・管理します
    • 今回のチュートリアル的には青い円柱の部分を1オーケーストレーターファイルで管理しています。

それではいってみましょう。

①Pythonプロジェクトを作成し、requirements.txtを作って必要なものをインストールする
Azure Functionsではまだ3.9が11月のあたまに出たばかりなので、3.8のプロジェクトを作ることにしました。このあたりはローカルでの普通にプロジェクトを作ってもらえればOKです。
requirements.txtには下記二つのライブラリをかき入れてくださいな

  • azure-functions
  • azure-functions-durable

②AzureポータルからAzure Functionsをつくる
これコマンドで作ってもいいんだけど、なぜか今回はポータルから作りました。どっちでもいいです。
「関数アプリ」を選択してAzure Functionsを作ります。お試しで触るだけなら従量課金プランかつ他のよくわからないなーっておもう設定は全部デフォルトにしておいてもらってもいいです。本番運用する人はちゃんと要件にあった設定を選んでくださいな。

何度でもいうけどこの「関数アプリ」という日本語訳はいかがなものか。

③PyCharmのTerminalからfunctionsのプロジェクトを作って行きます。
PyCharmのTerminalでもmac ターミナルでもwindows コマンドプロンプトでもいいんですが、Azure CLIを打っていきます。

  • func init
    • functions プロジェクトを作る宣言(initialize)
  • func new
    • スターター用functionを作ります宣言。テンプレートは「Durable Functions HTTP starter」を選択
  • func new
    • アクティビティ用functionを作ります宣言。テンプレートは「Durable Functions activity」を選択
  • func new
    • オーケストレーター用functionを作ります宣言。テンプレートは「Durable Functions Orchestrator」を選択

はい、上記コマンドを打つと、プロジェクト内に3つのfunctionディレクトリができたかと思います。

CLIから作ろうが何しようが.vscodeディレクトリはできあがる。

この__init__.py、実はサンプルコードがすでに記載された状態で作成されます。各functionsの中身を見てみましょう。

③-1スターター

async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
    client = df.DurableOrchestrationClient(starter)
    instance_id = await client.start_new(req.route_params["functionName"], None, None)

    logging.info(f"Started orchestration with ID = '{instance_id}'.")

    return client.create_check_status_response(req, instance_id)

httpリクエストを受け付けます、オーケストレーターはこれを使います、です。

③-2 オーケストレーター

def orchestrator_function(context: df.DurableOrchestrationContext):
    result1 = yield context.call_activity('funcActivity', "Tokyo")
    result2 = yield context.call_activity('funcActivity', "Seattle")
    result3 = yield context.call_activity('funcActivity', "London")
    return [result1, result2, result3]


main = df.Orchestrator.create(orchestrator_function)

funcActivityと書かれている部分は呼び出したいアクティビティ関数の名前を記載します。このチュートリアルコードでは、result1 -> result2 -> result3 の順で前のアクティビティ関数が終わるのを待ってから次のアクティビティ関数を呼び出しています。

これをファンアウトさせたければyieldさせずにfor文とかでアクティビティ関数を呼び出せばよく、ファンインさせたければcontext.task_allという関数にファンアウトの結果を渡してyieldさせます。

parallel_tasks = [ context.call_activity("F2", b) for b in work_batch ]
 outputs = yield context.task_all(parallel_tasks)

③-3 アクティビティ

本来一番やりたかった実コード部分ですね。チュートリアルでは何かやりたいことがあるわけでは当然ないので、とっても簡素なロジックコードが記載されています。

def main(name: str) -> str:
    return f"Hello {name}!"

アクティビティに引き渡された名前にHelloを付けて返すよ!!!

④②で作ったfunctions appにCLIでデプロイします。

(az loginは事前にやっておいてね~)
Terminalから下記コマンドをたたきませう

  • func azure functionapp publish [Functions Appの名前]

3つのFunctionまとめて同じFunctions Appへデプロイされます。

Terminalにはデプロイ作業の最後の方のログにHTTP URLが表示されると思いますので、このURLをたたいてあげてください。だいたいこんなかんじのURLなはず
https://%5BFunctions Appの名前].azurewebsites.net/api/orchestrators/[オーケストレータ関数の名前]?code=xxxxxxxxxxxxxxxxxxxxxxxxxxx

⑤ソースが正しく動いているか確認しよう

ここから先は↓の内容と一緒なのでドキュメント確認ください。
https://docs.microsoft.com/ja-jp/azure/azure-functions/durable/quickstart-python-vscode#test-the-function-locally
この章の4/5/6あたりです。

おしまい

というわけでチュートリアルをやってみようの会でした。コードを理解するというよりはDurable Functionsの仕組みを理解するのが大変だったかんじ。仕組みがわかればなんでコードがそうやってかかれているのかはとても読み解きやすいですね。

癖はあるけれども、慣れれば関数フローのどこで何が何回呼ばれて、どういう順番で実行されるのか、なんていうのが同じFunctions App内にコードとして残ってくれるので、IaC的にもFaaSの管理がしやすくなったのではないかしら。

今回はCLIでペロッとデプロイしましたが、コード管理していくならCI/CDちゃんと噛ませた方が安全ですね。今度手が空いたときにでもやろう。

すっげー今更ではありましたが、嫌いじゃないよ、Durable Functions.

というわけで以上です。

明日は7日目、Miki KurosawaさんがPyLadies Tokyo秋合宿のこと書いてくれるらしいYO
(まだ後半いっぱい空いてるのでみなさまのご参加お待ちしております!)

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください