サブオーケストレーション

オーケストレーター関数は、他のオーケストレーター関数を サブオーケストレーションとして呼び出すことができます。 サブオーケストレーションは、呼び出し元 (親) オーケストレーターの子として実行され、呼び出し元の観点からアクティビティのように動作します。値を返したり、親によってキャッチされた例外をスローしたり、 自動再試行をサポートしたりできます。

サブオーケストレーションを使用するタイミング

次の必要がある場合は、サブオーケストレーションを使用します。

  • 再利用可能なワークフロー構成要素を作成する: 複数の親オーケストレーションが呼び出すことができるように、複数ステップのワークフローを独自のオーケストレーターに抽出します。
  • 並行してオーケストレーションを実行する: 同じオーケストレーターの多数のインスタンスを同時にスケジュールし、それらのすべてが完了するまで待ちます。
  • 複雑なワークフローを整理する: 大規模なオーケストレーションを、1 つの長い関数ではなく、名前付きのテスト可能な部分に分割します。

サブオーケストレーションは、親オーケストレーションと同じアプリで定義する必要があります。 別のアプリでオーケストレーションを呼び出すには、代わりに HTTP 202 ポーリング パターンを使用します。 詳細については、「 HTTP 機能」を参照してください。

この記事の内容:

PowerShell では、サブオーケストレーションはスタンドアロン SDK: AzureFunctions.PowerShell.Durable.SDKでのみサポートされます。 スタンドアロン SDK と従来の組み込み SDK の違いについては、 移行ガイドを参照してください。

サブオーケストレーションを定義する

次の例は、複数のデバイスを設定する必要がある IoT シナリオを示しています。 この関数は、各デバイスで実行されるセットアップ ワークフローを表します。

分離ワーカー モデル
public static async Task DeviceProvisioningOrchestration(
    [OrchestrationTrigger] TaskOrchestrationContext context, string deviceId)
{
    // Step 1: Create an installation package in blob storage and return a SAS URL.
    Uri sasUrl = await context.CallActivityAsync<Uri>("CreateInstallationPackage", deviceId);

    // Step 2: Notify the device that the installation package is ready.
    await context.CallActivityAsync("SendPackageUrlToDevice", (deviceId, sasUrl));

    // Step 3: Wait for the device to acknowledge that it has downloaded the new package.
    await context.WaitForExternalEvent<bool>("DownloadCompletedAck");

    // Step 4: ...
}

プロセス内モデル
public static async Task DeviceProvisioningOrchestration(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string deviceId = context.GetInput<string>();

    // Step 1: Create an installation package in blob storage and return a SAS URL.
    Uri sasUrl = await context.CallActivityAsync<Uri>("CreateInstallationPackage", deviceId);

    // Step 2: Notify the device that the installation package is ready.
    await context.CallActivityAsync("SendPackageUrlToDevice", Tuple.Create(deviceId, sasUrl));

    // Step 3: Wait for the device to acknowledge that it has downloaded the new package.
    await context.WaitForExternalEvent<bool>("DownloadCompletedAck");

    // Step 4: ...
}
using Microsoft.DurableTask;

[DurableTask]
public class DeviceProvisioningOrchestration : TaskOrchestrator<string, object?>
{
    public override async Task<object?> RunAsync(TaskOrchestrationContext context, string deviceId)
    {
        // Step 1: Create an installation package in blob storage and return a SAS URL.
        Uri sasUrl = await context.CallActivityAsync<Uri>("CreateInstallationPackage", deviceId);

        // Step 2: Notify the device that the installation package is ready.
        await context.CallActivityAsync("SendPackageUrlToDevice", (deviceId, sasUrl.ToString()));

        // Step 3: Wait for the device to acknowledge that it has downloaded the new package.
        await context.WaitForExternalEvent<bool>("DownloadCompletedAck");

        // Step 4: ...
        return null;
    }
}

このオーケストレーター関数は、1 回限りのデバイスセットアップ用にスタンドアロンで実行することも、親オーケストレーターが 呼び出しサブオーケストレーター API を使用してサブオーケストレーションとしてスケジュールすることもできます。

サブオーケストレーションを並列で実行する

次の例は、親オーケストレーターが複数のサブオーケストレーションを並列に展開する方法を示しています。 一部の言語では、(親のインスタンス ID とインデックスから派生した) 決定論的な子インスタンス ID を使用して、再生時にサブオーケストレーションが重複しないようにします。

分離ワーカー モデル
[Function("ProvisionNewDevices")]
public static async Task ProvisionNewDevices(
    [OrchestrationTrigger] TaskOrchestrationContext context)
{
    string[] deviceIds = await context.CallActivityAsync<string[]>("GetNewDeviceIds");

    // Run multiple device provisioning flows in parallel
    var provisioningTasks = new List<Task>();
    foreach (string deviceId in deviceIds)
    {
        Task provisionTask = context.CallSubOrchestratorAsync("DeviceProvisioningOrchestration", deviceId);
        provisioningTasks.Add(provisionTask);
    }

    await Task.WhenAll(provisioningTasks);

    // ...
}

プロセス内モデル
[FunctionName("ProvisionNewDevices")]
public static async Task ProvisionNewDevices(
    [OrchestrationTrigger] IDurableOrchestrationContext context)
{
    string[] deviceIds = await context.CallActivityAsync<string[]>("GetNewDeviceIds");

    // Run multiple device provisioning flows in parallel
    var provisioningTasks = new List<Task>();
    foreach (string deviceId in deviceIds)
    {
        Task provisionTask = context.CallSubOrchestratorAsync("DeviceProvisioningOrchestration", deviceId);
        provisioningTasks.Add(provisionTask);
    }

    await Task.WhenAll(provisioningTasks);

    // ...
}

次のステップ

using Microsoft.DurableTask;

[DurableTask]
public class ProvisionNewDevices : TaskOrchestrator<object?, object?>
{
    public override async Task<object?> RunAsync(TaskOrchestrationContext context, object? input)
    {
        string[] deviceIds = await context.CallActivityAsync<string[]>("GetNewDeviceIds");

        // Run multiple device provisioning flows in parallel
        var provisioningTasks = new List<Task>();
        foreach (string deviceId in deviceIds)
        {
            Task provisionTask = context.CallSubOrchestratorAsync("DeviceProvisioningOrchestration", deviceId);
            provisioningTasks.Add(provisionTask);
        }

        await Task.WhenAll(provisioningTasks);
        return null;
    }
}

次のステップ