次の方法で共有


オーケストレーター関数のコード制約

Durable Functionsを使用してステートフル アプリを構築します。 これは、Azure Functions の拡張機能です。 orchestrator 関数を使用して、関数アプリ内の他のDurable Functions を管理します。 オーケストレーター関数はステートフルで信頼性が高く、長時間実行するように構築されています。

.NET、Python、およびJavaの Durable Task SDK を使用して、ステートフルでフォールト トレラントなワークフローを構築します。 オーケストレーターを使用して、アクティビティとサブオーケストレーションを調整します。 オーケストレーターはステートフルで信頼性が高く、長時間実行できるように構築されています。

オーケストレーター コードの制約

オーケストレーター関数は 、イベント ソーシングを 使用して、信頼性の高い実行を保証し、ローカル変数の状態を維持します。 オーケストレーター コードの 再生動作 により、オーケストレーター関数で記述できるコードの種類に制約が作成されます。 たとえば、オーケストレーター関数は 決定論的である必要があります。オーケストレーター関数は複数回再生し、毎回同じ結果を生成する必要があります。

オーケストレーターは 、イベント ソーシングを 使用して、信頼性の高い実行を保証し、ローカル変数の状態を維持します。 オーケストレーター コードの再生動作により、オーケストレーターで記述できるコードの種類に制約が作成されます。 たとえば、オーケストレーターは 決定論的である必要があります。オーケストレーターは複数回再生し、毎回同じ結果を生成する必要があります。

決定論的 API を使用する

コードが確定的であることを確認するのに役立つ簡単なガイドラインを次に示します。

オーケストレーター関数でターゲット言語から API を呼び出しますが、決定的な API のみを使用します。 決定論的 API は、呼び出されるタイミングや頻度に関係なく、同じ入力に対して常に同じ値を返します。

以下のセクションでは、決定論的 ではないため に回避する必要がある API とパターンに関するガイダンスを提供します。 これらの制限は、オーケストレーター関数にのみ適用されます。 他の関数型には、このような制限はありません。

コードが確定的であることを確認するのに役立つ簡単なガイドラインを次に示します。

オーケストレーターでターゲット言語から API を呼び出しますが、決定的な API のみを使用します。 決定論的 API は、呼び出されるタイミングや頻度に関係なく、同じ入力に対して常に同じ値を返します。

以下のセクションでは、決定論的 ではないため に回避する必要がある API とパターンに関するガイダンスを提供します。 これらの制限はオーケストレーターにのみ適用されます。 アクティビティにはこのような制限はありません。

この記事では、一般的なオーケストレーター コードの制約について説明しますが、包括的ではありません。 API が決定論的かどうかに焦点を当てます。 この考え方を使用すると、通常、この一覧を参照せずに安全に使用できる API を確認できます。

日付と時刻

時間ベースの API は非決定的であり、オーケストレーター関数では使用しないでください。 オーケストレーター関数の再生ごとに異なる値が生成されます。 代わりに、Durable Functions同等の API を使用して現在の日付または時刻を取得します。これは、再生間で一貫性が保たれます。

現在の時刻を取得するために、 、 、または同等の API を使用しないでください。 などのクラスも避ける必要があります。 インプロセス オーケストレーター関数.NET場合は、IDurableOrchestrationContext.CurrentUtcDateTime プロパティを使用して現在の時刻を取得します。 分離されたオーケストレーター関数.NET場合は、TaskOrchestrationContext.CurrentDateTimeUtc プロパティを使用して現在の時刻を取得します。

DateTime startTime = context.CurrentUtcDateTime;
// do some work
TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);

時間ベースの API は非決定的であり、オーケストレーターでは使用しないでください。 オーケストレーターの再生ごとに異なる値が生成されます。 代わりに、Durable Task SDK と同等の API を使用して現在の日付または時刻を取得します。これは、再生の間で一貫性が保たれます。

現在の時刻を取得するために、 、 、または同等の API を使用しないでください。 このようなクラスも避ける必要があります。 現在の時刻を取得するには、 プロパティを使用します。

using Microsoft.DurableTask;

public class TimerExample : TaskOrchestrator<object?, TimeSpan>
{
    public override async Task<TimeSpan> RunAsync(TaskOrchestrationContext context, object? input)
    {
        // Use context.CurrentUtcDateTime instead of DateTime.Now or DateTime.UtcNow
        DateTime startTime = context.CurrentUtcDateTime;

        // do some work
        await context.CallActivityAsync("DoWork", null);

        TimeSpan totalTime = context.CurrentUtcDateTime.Subtract(startTime);
        return totalTime;
    }
}

GUID と UUID

ランダムな GUID または UUID を返す API は、生成された値が再生ごとに異なるため、非決定的です。 言語によっては、決定論的 GUID または UUID を生成するための組み込みの API が使用できる場合があります。 それ以外の場合は、アクティビティ関数を使用して、ランダムに生成された GUID または UUID を返します。

のような API ではなく、コンテキスト オブジェクトの API を使用して、オーケストレーターの再生に安全なランダムな GUID を生成します。

Guid randomGuid = context.NewGuid();

オーケストレーション コンテキスト API で生成される GUID は 、タイプ 5 の UUID です。

ランダムな GUID または UUID を返す API は、生成された値が再生ごとに異なるため、非決定的です。 言語によっては、決定論的 GUID または UUID を生成するための組み込みの API が使用できる場合があります。 それ以外の場合は、アクティビティを使用してランダムに生成された GUID または UUID を返します。

のような API ではなく、コンテキスト オブジェクトの API を使用して、オーケストレーターの再生に安全なランダムな GUID を生成します。

using Microsoft.DurableTask;

public class GuidExample : TaskOrchestrator<object?, Guid>
{
    public override async Task<Guid> RunAsync(TaskOrchestrationContext context, object? input)
    {
        // Use context.NewGuid() instead of Guid.NewGuid()
        Guid randomGuid = context.NewGuid();
        return randomGuid;
    }
}

オーケストレーション コンテキスト API で生成される GUID は 、タイプ 5 の UUID です。

乱数

オーケストレーター関数に乱数を返すには、アクティビティ関数を使用します。 アクティビティ関数の戻り値は、オーケストレーション履歴に保存されるため、常に再生しても安全です。

または、オーケストレーター関数で固定シード値を持つ乱数ジェネレーターを直接使用することもできます。 この方法は、オーケストレーションの再生ごとに同じ数のシーケンスが生成されている限り安全です。

アクティビティを使用して、オーケストレーターに乱数を返します。 アクティビティの戻り値はオーケストレーション履歴に保存されるため、常に再生しても安全です。

または、オーケストレーターで固定シード値を持つ乱数ジェネレーターを直接使用することもできます。 この方法は、オーケストレーションの再生ごとに同じ数のシーケンスが生成されている限り安全です。

バインディング

オーケストレーション クライアントとエンティティ クライアントのバインドなど、オーケストレーター関数でバインドを使用しないでください。 入力バインドと出力バインドは、クライアントまたはアクティビティ関数でのみ使用します。 オーケストレーター関数は複数回再生できるため、外部システムで非決定的で重複する I/O が発生します。

オーケストレーターは、外部システムで直接 I/O 操作を実行しないでください。 I/O 操作をアクティビティに移動します。 オーケストレーターは複数回再生できるため、外部システムで非決定的で重複する I/O が発生します。

静的変数

静的変数は時間の経過と同時に変化する可能性があります。オーケストレーター関数では安全ではありません。 オーケストレーター関数では静的変数を使用しないでください。値は時間の経過と同時に変化し、結果として非決定的なランタイム動作が発生する可能性があるためです。 代わりに、定数を使用するか、静的変数の使用をアクティビティ関数に制限します。

静的変数は時間の経過と同時に変化する可能性があります。オーケストレーターにとって安全ではありません。 オーケストレーターでは静的変数を使用しないでください。値は時間の経過と同時に変化し、結果として非決定的なランタイム動作が発生する可能性があるためです。 代わりに、定数を使用するか、静的変数の使用をアクティビティに制限します。

オーケストレーター関数の外部でも、Azure Functionsで静的変数を使用すると、複数の関数の実行に静的な状態が保持される保証がないため、さまざまな理由で問題になる可能性があります。 アクティビティ関数やエンティティ関数でのメモリ内キャッシュのベスト エフォートなど、特定のユース ケースを除き、静的変数は避けてください。

環境変数

オーケストレーター関数の環境変数は時間の経過と同時に変化し、結果として非決定的なランタイム動作が発生する可能性があります。 オーケストレーター関数で環境変数で定義された構成が必要な場合は、構成値を入力として、またはアクティビティ関数の戻り値としてオーケストレーター関数に渡す必要があります。

オーケストレーターの環境変数は時間の経過と同時に変化し、結果として非決定的なランタイム動作が発生する可能性があります。 オーケストレーターで環境変数で構成を定義する必要がある場合は、構成値を入力またはアクティビティの戻り値としてオーケストレーターに渡す必要があります。

ネットワークと HTTP

アクティビティ関数を使用して、送信ネットワーク呼び出しを行います。 オーケストレーター関数から HTTP 呼び出しを行う必要がある場合は、 永続的な HTTP API を使用することもできます。

アクティビティを使用してネットワーク呼び出しを行います。 オーケストレーターは、直接 HTTP 呼び出しやその他のネットワーク要求を行うべきではありません。これらの操作は非決定的であるためです。

スレッド ブロック API

sleep などの API をブロックすると、オーケストレーター関数のパフォーマンスとスケールの問題が発生し、Azure Functions従量課金プランで不要な実行時間の料金が発生する可能性があります。 使用可能な場合は、代替手段を使用します。 たとえば、 Durable タイマー を使用して、再生しても安全で、オーケストレーターの実行時間にはカウントされない遅延を作成します。

"スリープ" などの API をブロックすると、オーケストレーターのパフォーマンスとスケールの問題が発生する可能性があるため、回避する必要があります。 永続的タイマーを使用して、再生に安全な遅延を作成します。

「> <」や「> <」の代わりに「> <」を使用します。

// Don't use Task.Delay() or Thread.Sleep()
// Use context.CreateTimer() instead
await context.CreateTimer(context.CurrentUtcDateTime.AddMinutes(5), CancellationToken.None);

非同期 API

オーケストレーション トリガーのコンテキスト オブジェクトによって定義された操作を除き、オーケストレーター コードで非同期操作を開始しないでください。 たとえば、javaScript では、Task.RunTask.DelayHttpClient.SendAsync、または .NET setTimeout および setInterval を使用しないでください。 オーケストレーター関数では、アクティビティ関数のスケジュール設定など、Durable SDK API を使用して非同期作業のみをスケジュールする必要があります。 その他の種類の非同期呼び出しは、アクティビティ関数内で実行する必要があります。

オーケストレーター コードは、オーケストレーション コンテキスト オブジェクトによって定義された操作を除き、非同期操作を開始してはなりません。 たとえば、.NETでは、Task.RunTask.DelayHttpClient.SendAsyncは使用しないでください。 オーケストレーターでは、アクティビティのスケジュールなど、Durable Task SDK API を使用して非同期作業のみをスケジュールする必要があります。 その他の種類の非同期呼び出しは、アクティビティ内で実行する必要があります。

非同期 JavaScript 関数

JavaScript オーケストレーター関数を同期ジェネレーター関数として宣言します。 Node.js ランタイムでは関数の決定論的な動作が保証されないため、JavaScript オーケストレーター関数をとして宣言しないでください。

Pythonコルーチン

オーケストレーター関数Pythonコルーチンとして宣言しないでください。 コルーチンセマンティクスはDurable Functions再生モデルと一致しないため、async キーワードを使用しないでください。 オーケストレーター関数Pythonジェネレーターとして宣言し、yield API で await ではなく context を使用します。

Pythonオーケストレーターをコルーチンとして宣言してはいけません。 つまり、コルーチン セマンティクスが Durable Task 再生モデルと一致しないため、async キーワードを使用してPythonオーケストレーターを宣言しないでください。 オーケストレーター Python必ずジェネレーターとして宣言する必要があります。つまり、コンテキスト API を呼び出すときは、yield ではなく await を使用する必要があります。

from durabletask import task

# CORRECT - use yield (generator function)
def my_orchestrator(ctx: task.OrchestrationContext, input: str):
    result = yield ctx.call_activity(my_activity, input=input)
    return result

# WRONG - don't use async/await
async def bad_orchestrator(ctx: task.OrchestrationContext, input: str):
    result = await ctx.call_activity(my_activity, input=input)  # This won't work!
    return result

.NET のスレッド API

Durable Task Framework は、1 つのスレッドでオーケストレーター コードを実行し、他のスレッドと対話することはできません。 オーケストレーションの実行でワーカー プール スレッドで非同期継続を実行すると、非決定的な実行またはデッドロックが発生する可能性があります。 このため、オーケストレーター関数ではスレッド API をほとんど使用しないでください。 たとえば、オーケストレーター関数で を使用して、オーケストレーター関数の元の でタスクの継続が確実に実行されるようにしないでください。

Durable Task Framework は、オーケストレーター関数で非オーケストレーター スレッドを誤って使用した場合の検出を試みます。 違反が見つかると、フレームワークは NonDeterministicOrchestrationException 例外をスローします。 ただし、この検出動作ではすべての違反がキャッチされるわけではありません。また、それに依存しないでください。

Durable Task Framework は、1 つのスレッドでオーケストレーター コードを実行し、他のスレッドと対話することはできません。 オーケストレーションの実行でワーカー プール スレッドで非同期継続を実行すると、非決定的な実行またはデッドロックが発生する可能性があります。 このため、オーケストレーターはスレッド API をほとんど使用しないでください。 たとえば、オーケストレーターで を使用して、オーケストレーターの元の でタスクの継続が確実に実行されるようにしないでください。

Durable Task Framework は、オーケストレーターで非オーケストレーター スレッドを誤って使用した場合の検出を試みます。 違反が見つかると、フレームワークは NonDeterministicOrchestrationException 例外を スローします。 ただし、この検出動作ではすべての違反がキャッチされるわけではありません。また、それに依存しないでください。

バージョン管理

永続的オーケストレーションは、数日、数ヶ月、数年、または無限に実行することができます。 実行中のオーケストレーションに影響を与えるコード変更は再生動作を中断する可能性があるため、アプリを更新する前に慎重に計画してください。 詳細については、「 バージョン管理」を参照してください。

耐久性のあるオーケストレーションは、日、月、年、あるいは無期限に実行できます。 実行中のオーケストレーションに影響を与えるコード変更は再生動作を中断する可能性があるため、アプリを更新する前に慎重に計画してください。 一般的なバージョン管理戦略には、サイド バイ サイドデプロイと、バージョン固有のタスク ハブ名の使用が含まれます。

永続タスク

このセクションでは、Durable Task Framework の内部実装の詳細について説明します。 Durable Functionsを使用するためにこの情報を知る必要はありませんが、再生動作を説明するのに役立ちます。

オーケストレーター関数で安全に待機できるタスクは、 永続的なタスクと呼ばれることもあります。 Durable Task Framework は、これらのタスクを作成および管理します。 たとえば、.NET オーケストレーター関数の CallActivityAsyncWaitForExternalEventCreateTimer によって返されるタスクが含まれます。

.NET内の TaskCompletionSource オブジェクトの一覧は、これらの永続的なタスクを内部的に管理します。 再生中に、オーケストレーター コードによってこれらのタスクが作成されます。 ディスパッチャーは、対応する履歴イベントを列挙すると、それらを完了します。

ランタイムは、履歴を再生するまで、1 つのスレッドでタスクを同期的に実行します。 履歴の再生が終了するまでに永続的なタスクが完了しない場合、ランタイムは適切なアクションを実行します。 たとえば、ランタイムはメッセージをエンキューしてアクティビティ関数を呼び出すことができます。

ランタイム動作により、オーケストレーター関数が非持続的なタスクで「await」または「result」を使用できない理由が説明されます。 ディスパッチャー スレッドはタスクの完了を待機できません。また、そのタスクからのコールバックによってオーケストレーター関数の追跡状態が破損する可能性があります。 ランタイムには、これらの違反の検出に役立つチェックが含まれています。

Durable Task Framework がオーケストレーター関数を実行する方法の詳細については、GitHub の Durable Task ソース コードを参照してください。 特に、TaskOrchestrationExecutor.cs および TaskOrchestrationContext.cs を参照してください。

オーケストレーターで安全に待機できるタスクは、 永続的なタスクと呼ばれることもあります。 Durable Task Framework は、これらのタスクを作成および管理します。 たとえば、CallActivityAsyncWaitForExternalEvent、.NET オーケストレーターの CreateTimer によって返されるタスクが挙げられます。

.NET内の TaskCompletionSource オブジェクトの一覧は、これらの永続的なタスクを内部的に管理します。 再生中に、オーケストレーター コードによってこれらのタスクが作成されます。 ディスパッチャーは、対応する履歴イベントを列挙すると、それらを完了します。

ランタイムは、履歴を再生するまで、1 つのスレッドでタスクを同期的に実行します。 履歴の再生が終了するまでに永続的なタスクが完了しない場合、ランタイムは適切なアクションを実行します。 たとえば、ランタイムはメッセージをエンキューしてアクティビティを呼び出すことができます。

オーケストレータが`yield`または`await`を非永続的なタスクで使用できない理由を、このランタイム動作は説明します。 ディスパッチャー スレッドはタスクの完了を待機できません。また、そのタスクからのコールバックによってオーケストレーターの追跡状態が破損する可能性があります。 ランタイムには、これらの違反の検出に役立つチェックが含まれています。

Durable Task Framework がオーケストレーターを実行する方法の詳細については、GitHub の Durable Task ソース コードを参照してください。 特に、TaskOrchestrationExecutor.cs および TaskOrchestrationContext.cs を参照してください。

次のステップ

サブオーケストレーションを呼び出す方法を学ぶ

バージョン管理を処理する方法について説明します

Durable Task SDK を始めましょう