オーケストレーター関数は、コード ベースのワークフローとして他の関数の実行を調整します。 オーケストレーター関数には、次の特性があります。
- 手続き型コードを使用して関数ワークフローを定義します。 宣言型スキーマやデザイナーは必要ありません。
- 他の関数を同期的および非同期的に呼び出すことができます。 呼び出された関数からの出力は、ローカル変数に保存できます。
- 耐久性と信頼性が高いように設計されています。 関数が または 演算子を呼び出すと、実行の進行状況がチェックポイントとして自動的に保存されます。 プロセスがリサイクルされるか、VM が再起動しても、ローカル状態は失われません。
- 実行時間が長い場合があります。 オーケストレーション インスタンスの合計有効期間は、秒、日、または月にすることができます。また、インスタンスを決して終了するように構成することもできます。
この記事では、オーケストレーター関数の概要と、それらがさまざまなアプリ開発の課題の解決にどのように役立つかについて説明します。
Durable Functions アプリで使用できる関数の種類については、「Durable Task プログラミング モデルを参照してください。
Durable Task SDK は、Durable Functionsと同じオーケストレーター機能を提供しますが、Durable Task Scheduler によってサポートされるスタンドアロン アプリケーションとして実行されます。
オーケストレーション アイデンティティ
オーケストレーションの各 インスタンス には、インスタンス ID とも呼ばれる インスタンス識別子があります。 既定では、各インスタンス ID は自動生成されたグローバル一意識別子 (GUID) です。 ただし、インスタンス ID には、ユーザーが生成した任意の文字列値を指定することもできます。 各オーケストレーション インスタンス ID は 、タスク ハブ内で一意である必要があります。
インスタンス ID には、次の規則が適用されます。
- 1 ~ 100 文字にする必要があります。
- で始めてはなりません。
- 、、、または文字を含めてはなりません。
- コントロール文字を含めてはなりません。
注
可能な限り、自動生成されたインスタンス ID を使用します。 ユーザー生成インスタンス ID は、オーケストレーション インスタンスと外部アプリケーション固有のエンティティ (発注書やドキュメントなど) の間に 1 対 1 のマッピングがあるシナリオを対象としています。
注
文字制限ルールの実際の適用は、アプリが使用する ストレージ プロバイダー によって異なる場合があります。 正しい動作と互換性を確保するには、上記のインスタンス ID 規則に従います。
オーケストレーションのインスタンス ID は、ほとんどの インスタンス管理操作に必要なパラメーターです。 インスタンス ID は、診断にも重要です。 たとえば、トラブルシューティングや分析のために Application Insights で オーケストレーション追跡データを検索 するときに使用します。 このため、生成されたインスタンス ID を外部の場所に保存して、データベースやアプリケーション ログなど、後で簡単に参照できるようにします。
オーケストレーションのインスタンス ID は、ほとんどのインスタンス管理操作に必要なパラメーターです。 インスタンス ID は診断にも重要であるため、生成されたインスタンス ID を外部の場所に保存して、データベースやアプリケーション ログなど、後で簡単に参照できるようにします。
Reliability
オーケストレーター関数は 、イベント ソーシング 設計パターンを使用して、実行状態を確実に維持します。 Durable Task Framework では、オーケストレーションの現在の状態を直接格納する代わりに、追加専用ストアを使用して、関数オーケストレーションが実行する一連のアクションをすべて記録します。 追加専用ストアには、完全なランタイム状態 のダンプ に比べて多くの利点があります。 パフォーマンス、スケーラビリティ、応答性の向上などの利点があります。 また、トランザクション データ、完全な監査証跡、履歴の最終的な整合性も得られます。 監査証跡は、信頼性の高い補正アクションをサポートします。
Durable Task Framework では、イベント ソーシングが透過的に使用されます。 バックグラウンドでは、オーケストレーター関数は C# で await 演算子を使用し、JavaScript と Python では yield 演算子を使用します。 これらの演算子は、オーケストレーター スレッドの制御を Durable Task Framework ディスパッチャーに戻します。 Javaでは、タスクで .await() を呼び出すと、Throwable のカスタム インスタンスを介してディスパッチャーに制御が戻されます。 その後、ディスパッチャーは、オーケストレーター関数がストレージにスケジュールする新しいアクションをコミットします。 アクションの例としては、1 つ以上の子関数を呼び出したり、永続的なタイマーをスケジュールしたりすることが含まれます。 透過的コミット アクションは、追加専用ログと同様に、すべての新しいイベントをストレージに追加することで、オーケストレーション インスタンスの実行履歴を更新します。 同様に、コミット アクションは、実際の作業をスケジュールするメッセージをストレージに作成します。 この時点で、オーケストレーター関数をメモリからアンロードできます。
既定では、Durable Functionsはランタイム状態ストアとしてAzure Storageを使用しますが、他の storage プロバイダーもサポートされています。
オーケストレーション関数がより多くの処理を行う場合 (応答メッセージを受信した場合や永続的なタイマーが期限切れになった場合など)、オーケストレーターは起動し、関数全体を最初から再実行してローカル状態を再構築します。 再生中に、コードが関数を呼び出そうとする (またはその他の非同期作業を行う) 場合、Durable Task Framework は現在のオーケストレーションの実行履歴を参照します。 アクティビティが既に実行され、結果が生成されたと検出された場合は、その関数の結果が再生され、オーケストレーター コードは引き続き実行されます。 再生は、関数コードが完了するか、新しい非同期作業をスケジュールするまで続行されます。
注
再生パターンが正しく確実に機能するためには、オーケストレーター関数コードが 決定論的である必要があります。 非決定的オーケストレーター コードでは、ランタイム エラーまたはその他の予期しない動作が発生する可能性があります。 オーケストレーター関数のコード制限の詳細については、「 オーケストレーター関数のコード制約」を参照してください。
注
オーケストレーター関数がログ メッセージを出力すると、再生動作によって重複するログ メッセージが出力される可能性があります。 この動作が発生する理由とその回避方法については、「 アプリのログ記録」を参照してください。
オーケストレーションの履歴
Durable Task Framework のイベント ソーシング動作は、記述するオーケストレーター関数コードと密接に結び付けられます。 次に示す例のように、アクティビティ チェーン オーケストレーター関数を持っているとします。
[Function("HelloCities")]
public static async Task<List<string>> Run(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));
// Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
return outputs;
}
プロセス内モデル
[FunctionName("HelloCities")]
public static async Task<List<string>> Run(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));
// Return ["Hello Tokyo!", "Hello Seattle!", "Hello London!"].
return outputs;
}
using Microsoft.DurableTask;
[DurableTask]
public class HelloCities : TaskOrchestrator<object?, List<string>>
{
public override async Task<List<string>> RunAsync(TaskOrchestrationContext context, object? input)
{
var outputs = new List<string>();
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Tokyo"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "Seattle"));
outputs.Add(await context.CallActivityAsync<string>("SayHello", "London"));
return outputs;
}
}
アクティビティ関数がスケジュールされるたびに、Durable Task Framework はさまざまなチェックポイントで関数の実行状態を保存します。 各チェックポイントで、フレームワークは状態を永続的なストレージ バックエンドに保存します。 この状態はオーケストレーション 履歴と呼ばれます。
履歴テーブル
一般に、Durable Task Framework は各チェックポイントで次の処理を行います。
- 実行履歴を永続ストレージに保存します。
- オーケストレーターが呼び出す関数のメッセージをエンキューします。
- オーケストレーター自身のメッセージ、例えば永続的なタイマーメッセージなどをエンキューします。
チェックポイントが完了すると、オーケストレーター関数は、さらに作業が必要になるまでメモリから削除できます。
注
Azure Storageでは、データの保存時にテーブル ストレージとキューの間のデータ整合性に関するトランザクション上の保証は提供されません。 エラーを処理するために、Durable Functions Azure Storage プロバイダーは、イベント整合性 パターンを使用します。 これらのパターンは、チェックポイントの途中でクラッシュや接続の損失が発生した場合にデータが失われないようにするのに役立ちます。 Durable Functions Microsoft SQL Server (MSSQL) ストレージ プロバイダー などの代替ストレージ プロバイダーは、より強力な整合性の保証を提供する場合があります。
前に示した関数が完了すると、その履歴は Table Storage の次の表のデータのようになります。 エントリは例示のために省略されています。
| PartitionKey(インスタンスID) | イベントの種類 | タイムスタンプ | Input | 名前 | 結果 | ステータス |
|---|---|---|---|---|---|---|
| eaee885b | 実行開始 | 2021-05-05T18:45:28.852Z | null 値 | HelloCities | ||
| eaee885b | オーケストレーター開始 (OrchestratorStarted) | 2021-05-05T18:45:32.362Z | ||||
| eaee885b | タスクスケジュール済み | 2021-05-05T18:45:32.670Z | セイハロー | |||
| eaee885b | OrchestratorCompleted | 2021-05-05T18:45:32.670Z | ||||
| eaee885b | TaskCompleted | 2021-05-05T18:45:34.201Z | """Hello Tokyo!"" | |||
| eaee885b | オーケストレーター開始 (OrchestratorStarted) | 2021-05-05T18:45:34.232Z | ||||
| eaee885b | タスクスケジュール済み | 2021-05-05T18:45:34.435Z | セイハロー | |||
| eaee885b | OrchestratorCompleted | 2021-05-05T18:45:34.435Z | ||||
| eaee885b | TaskCompleted | 2021-05-05T18:45:34.763Z | """Hello Seattle!""" | |||
| eaee885b | オーケストレーター開始 (OrchestratorStarted) | 2021-05-05T18:45:34.857Z | ||||
| eaee885b | タスクスケジュール済み | 2021-05-05T18:45:34.857Z | セイハロー | |||
| eaee885b | OrchestratorCompleted | 2021-05-05T18:45:34.857Z | ||||
| eaee885b | TaskCompleted | 2021-05-05T18:45:34.919Z | """Hello London!""" | |||
| eaee885b | オーケストレーター開始 (OrchestratorStarted) | 2021-05-05T18:45:35.032Z | ||||
| eaee885b | OrchestratorCompleted | 2021-05-05T18:45:35.044Z | ||||
| eaee885b | 実行完了 | 2021-05-05T18:45:35.044Z | "["Hello Tokyo!"","Hello Seattle!"","Hello London!""" | 完了済み |
テーブル列には、次の値が含まれています。
- PartitionKey: オーケストレーションのインスタンス ID。
- EventType: イベントの型。 すべての履歴イベントの種類の詳細については、「Durable Task Framework History Events」を参照してください。
- タイムスタンプ: 履歴イベントの協定世界時タイムスタンプ。
- 入力: 関数の JSON 形式の入力。
- 名前: 呼び出された関数の名前。
- 結果: 関数の出力 (具体的には、その戻り値)。
Warnung
この表はデバッグ ツールとして役立ちますが、Durable Functions拡張機能の進化に伴って、その形式と内容が変更される可能性があります。
タスクの完了を待機した後に関数が再開されるたびに、Durable Task Framework によってオーケストレーター関数が最初から再実行されます。 再実行のたびに、実行履歴を調べて、現在の非同期タスクが完了しているかどうかを判断します。 実行履歴にタスクが既に完了していることを示す場合、フレームワークはそのタスクの出力を再生し、次のタスクに進みます。 このプロセスは、実行履歴全体が再生されるまで続行されます。 現在の実行履歴が再生されると、ローカル変数は以前の値に復元されます。
特徴とパターン
次のセクションでは、オーケストレーター関数の機能とパターンについて説明します。
サブオーケストレーション
オーケストレーター関数は、アクティビティ関数だけでなく、他のオーケストレーター関数も呼び出すことができます。 たとえば、オーケストレーター関数のライブラリから大規模なオーケストレーションを構築できます。 または、オーケストレーター関数の複数のインスタンスを並列で実行できます。
詳細と例については、「Durable Functions (Azure Functions)」の「サブオーケストレーション」を参照してください。
持続的タイマー
オーケストレーションでは、遅延を実装したり、非同期アクションのタイムアウト処理を設定したりするために 、永続的タイマー をスケジュールできます。 言語ネイティブ API ではなく、オーケストレーター関数で永続的タイマーを使用します。
詳細と例については、Durable Functions (Azure Functions) の Timers を参照してください。
外部イベント
オーケストレーター関数は、外部イベントがオーケストレーション インスタンスを更新するのを待機できます。 このDurable Functions機能は、多くの場合、人間の対話やその他の外部コールバックを処理するのに役立ちます。
詳細と例については、「
エラー処理
オーケストレーター関数では、プログラミング言語のエラー処理機能を使用できます。 オーケストレーション コードでは、 などの既存のパターンがサポートされています。
オーケストレーター関数は、呼び出すアクティビティまたはサブオーケストレーター関数に再試行ポリシーを追加することもできます。 アクティビティまたはサブオーケストレーター関数が例外で失敗した場合、指定された再試行ポリシーは自動的に遅延し、指定された回数まで実行を再試行できます。
注
オーケストレーター関数にハンドルされない例外がある場合、オーケストレーション インスタンスは 状態で終了します。 オーケストレーション インスタンスは、失敗した後は再試行できません。
詳細と例については、「
クリティカル セクション (Durable Functions 2.x、現在.NETのみ)
オーケストレーション インスタンスはシングル スレッドであるため、オーケストレーション 内 で競合状態は問題になりません。 ただし、オーケストレーションが外部システムとやり取りする場合、競合状態が発生する可能性があります。 外部システムと対話するときの競合状態を軽減するために、オーケストレーター関数は、.NET の メソッドを使用して、LockAsyncを定義できます。
次のサンプル コードは、クリティカル セクションを定義するオーケストレーター関数を示しています。 メソッドを使用してクリティカル セクションを入力します。 このメソッドでは、永続的 なエンティティへの 1 つ以上の参照を渡す必要があります。これは、永続的にロック状態を管理します。 このオーケストレーションの 1 つのインスタンスのみが、クリティカル セクションのコードを一度に実行できます。
[FunctionName("Synchronize")]
public static async Task Synchronize(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
var lockId = new EntityId("LockEntity", "MyLockIdentifier");
using (await context.LockAsync(lockId))
{
// Critical section. Only one orchestration can enter at a time.
}
}
メソッドは永続的なロックを取得し、破棄されたときにクリティカル セクションを終了するを返します。 この 結果を ブロックと共に使用して、クリティカル セクションの構文表現を取得できます。 オーケストレーター関数がクリティカル セクションに入ると、そのコード ブロックを実行できるインスタンスは 1 つだけです。 クリティカル セクションに入ろうとするその他のインスタンスは、前のインスタンスがクリティカル セクションを終了するまでブロックされます。
重要なセクション機能は、永続エンティティへの変更を調整する場合にも役立ちます。 重要なセクションの詳細については、「エンティティの 調整」を参照してください。
注
重要なセクションは、Durable Functions 2.0 で入手できます。 現時点では、.NETインプロセス オーケストレーションのみがこの機能を実装します。 エンティティとクリティカルセクションは、.NET 分離ワーカーオーケストレーションのDurable Functionsでまだ使用できません。
HTTP エンドポイントの呼び出し (Durable Functions 2.x)
オーケストレーター関数のコード制約で説明されているように、 オーケストレーター関数は I/O 操作を実行できません。 この制限の一般的な回避策は、アクティビティ関数で I/O 操作を実行する必要があるコードをラップすることです。 外部システムとやり取りするオーケストレーションでは、アクティビティ関数を頻繁に使用して HTTP 呼び出しを行い、結果をオーケストレーションに返します。
この一般的なパターンを合理化するために、オーケストレーター関数では、 メソッドを使用して HTTP API を直接呼び出すことができます。
[Function("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
[OrchestrationTrigger] TaskOrchestrationContext context)
{
Uri url = context.GetInput<Uri>();
// Make an HTTP GET request to the specified endpoint.
DurableHttpResponse response = await context.CallHttpAsync(
method: HttpMethod.Get,
uri: url,
content: null,
retryOptions: null);
if ((int)response.StatusCode == 400)
{
// Handle error codes.
}
}
プロセス内モデル
[FunctionName("CheckSiteAvailable")]
public static async Task CheckSiteAvailable(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
Uri url = context.GetInput<Uri>();
// Make an HTTP GET request to the specified endpoint.
DurableHttpResponse response =
await context.CallHttpAsync(HttpMethod.Get, url);
if ((int)response.StatusCode == 400)
{
// Handle error codes.
}
}
このメソッドは、基本的な要求/応答パターンをサポートするだけでなく、一般的な非同期 HTTP 202 ポーリング パターンの自動処理をサポートします。 また、 マネージド ID を使用した外部サービスでの認証もサポートしています。
詳細および詳細な例については、 HTTP 機能を参照してください。
注
オーケストレーター関数から直接 HTTP エンドポイントを呼び出すことは、Durable Functions 2.0 以降で使用できます。
複数のパラメーター
アクティビティ関数に複数のパラメーターを直接渡すことはできません。 オブジェクトまたは複合オブジェクトの配列を渡すことが推奨されます。
.NETでは、レコード型または ValueTuple オブジェクトを使用して、複数のパラメーターを渡すことができます。
public record CourseInfo(string Major, int UniversityYear);
[Function("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
[OrchestrationTrigger] TaskOrchestrationContext context, int universityYear)
{
CourseInfo courseInfo = new("ComputerScience", universityYear);
object courseRecommendations = await context.CallActivityAsync<object>(
"CourseRecommendations", courseInfo);
return courseRecommendations;
}
プロセス内モデル
.NETでは、ValueTuple オブジェクトを使用して複数のパラメーターを渡すこともできます。 次の例では、C# 7 で追加された ValueTuple 機能を使用します。
[FunctionName("GetCourseRecommendations")]
public static async Task<object> RunOrchestrator(
[OrchestrationTrigger] IDurableOrchestrationContext context)
{
string major = "ComputerScience";
int universityYear = context.GetInput<int>();
object courseRecommendations = await context.CallActivityAsync<object>(
"CourseRecommendations",
(major, universityYear));
return courseRecommendations;
}
.NETでは、レコード型またはタプルを使用して、複数のパラメーターを 1 つの複合オブジェクトとして渡すことができます。
using Microsoft.DurableTask;
public record LocationInfo(string City, string State);
[DurableTask]
public class GetWeatherOrchestration : TaskOrchestrator<object?, string>
{
public override async Task<string> RunAsync(TaskOrchestrationContext context, object? input)
{
var location = new LocationInfo("Seattle", "WA");
string weather = await context.CallActivityAsync<string>("GetWeather", location);
return weather;
}
}
次のステップ
オーケストレーター関数のコード制約
Durable Task SDK を始めましょう