Durable Functions を使うと、基本的に Azure の Storage で状態が管理されますが、久ぶりに使ったときに基本的な内容が改めて全く記憶がなかったのでメモしました。
状態管理
Durable Functions は、Azure Storage の Blob/Queue/Table で状態の管理が行われています。
Table
Table では、以下2つが作成されて状態の管理が行われます。
- History : 実行の履歴が記録されます。
- Instances : InstanceId 毎にステートが記録されます。
テーブル名には prefix でTaskHub名がついています。
TaskHub名は、デフォルト値が DurableFunctionsHub です。そのため、デフォルトのテーブル名は、
DurableFunctionsHubHistory
とDurableFunctionsHubInstances
です。host.json で設定したり、starter の関数で指定できます(ドキュメントはこちら)。
Instances テーブルだけ見るとステートソーシングな感じですが、実際の管理は History テーブルを使ってイベントソーシングでして "Durable" にしています。
Queue
Queue は、役割に応じて2種類あります。
- control : 主にオーケストレーターがトリガーするための queue。
- workitems : Activity Trigger 用の queue
queue の名前は、Table 同様に TaskHub名が prefix としてにつきます。durableFunctionshub-control-00
~ 03
と durableFunctionshub-workitems
です。
基本的な動きのイメージは、
- starter が control queue にエンキューして 起動停止。
- control queue をトリガーに Orchestrator が起動。workitems queue にエンキューして停止。
- workitems queue をトリガーに Activity Function が起動。処理が終わったらcontrol queue にエンキューして起動終了。
- control queue をトリガーに Orchestrator が再起動。workitems queue にエンキューして停止。
って感じのを Orchestrator の処理が終わるまで繰り返すのですね。
Blob は、leases 用の Container が作られます。また、インプットのデータがでかいときに使われる?今回実装を見ててあまり気になるところがなかったので見ても調べてもいません(てきとー)。気になるタイミングが出たら追記します。
起動
Durable Functions の基本構成
Durable Functions は、基本的に以下の3つで構成されています。
- starter: Orchestrator を起動するための function。タイマーや Http 、Queue トリガーといった方法で起動します。
- Orchestrator function: 主に Activity function をオーケストレートするための function。Durable Functions には色んなパターンが紹介されていますが、それらは Orchestrator functionでの構成の違いによって作られます。構成する要素としては、Activity function, Sub-orchestrations, タイマー, 外部イベントや最近出た Entity function などです。
- Activity function: 実際の処理を書くところです。
starter の起動
メソッドに OrchestrationClientAttribute をつけることで starter として動作します。この起動に関することは こちら にまとまってます。
starter に関してまず知っておくべきことは、StartNewAsync
メソッドを実行することで Orchestorator が起動するということです。
もう少し具体的な話だと、StartNewAsync
メソッドの中で、control queue に message を投げています。その結果、その queue をトリガーにして Orchestrator function( つまり [OrchestrationTrigger]
を持ってるメソッド)が起動します。
実装をさらっとみたところ
DurableTask.Core.TaskHubClient
class のInternalCreateOrchestrationInstanceWithRaisedEventAsync
メソッドで contorol-XX のキューにメッセージ投げています。
contorol queue はデフォルトで0~3の4つあります。orchestrator の instanceId をハッシュ化して PartitionCount(デフォは4)で割って0-3の数字を決めて振り分けてるので、ようはランダムに振り分けてるって感じですね。
StartNewAsync
時に、Orchestrator の Instance を管理する InstanceId が付与します。メソッドの引数に渡さなければ GUID が付与されますし、引数で渡して自分で管理することも可能です。InstanceId の最大の Length は 256 です。状態の管理や、外部イベントから呼び出すときに重要になってきます。
Orchestrator の起動
メソッドの引数に OrchestrationTriggerAttribute をつけることで Orchestorator として動作します。OrchestrationTrigger の動作についてはこちらのドキュメントにまとまっています。
ざっくり把握しておくべきこととしては、Orchestrator は control queue をトリガーに動きます。Activity function を呼ぶ( = workitems queue に message 投げる)毎に停止し、Activity function が終わる(= control queue に message が入る)毎に再開します。
Activity 関数の実行
ActivityTriggerAttribute をメソッドの引数につけることで Activity function となります。動作はこちらのドキュメント にまとまっています。
終わりに
といった感じでどんどん興味がわいてくるところですが、だんだん内容が薄くなってきたので今回はここまでにします。
近所の映画館で「天気の子」が 4DX でやってるようで見にいきたいたくなったので、ここまでにしました...♪