Suborchestrierungen

Orchestratorfunktionen können andere Orchestratorfunktionen als untergeordnete Orchestrierungen aufrufen. Eine untergeordnete Orchestrierung wird als untergeordnetes Element des aufrufenden (übergeordneten) Orchestrators ausgeführt und verhält sich wie eine Aktivität aus der Perspektive des Aufrufers: Sie kann einen Wert zurückgeben, Ausnahmen auslösen, die vom übergeordneten Element abgefangen werden, und automatische Wiederholungsversuche unterstützen.

Wann Unter-Orchestrierungen verwendet werden sollten

Verwenden Sie Sub-Orchestrierungen, wenn Sie Folgendes benötigen:

  • Erstellen sie wiederverwendbare Workflowbausteine: Extrahieren Sie einen mehrstufigen Workflow in einen eigenen Orchestrator, damit mehrere übergeordnete Orchestrierungen sie aufrufen können.
  • Paralleles Auffächern von Orchestrierungen: Planen Sie zahlreiche Instanzen desselben Orchestrators gleichzeitig, und warten Sie, bis alle Instanzen abgeschlossen sind.
  • Organisieren komplexer Workflows: Unterteilen Sie eine große Orchestrierung in benannte, testbare Stücke anstelle einer einzelnen langen Funktion.

Hinweis

Sub-Orchestrierungen müssen in derselben App wie die übergeordnete Orchestrierung definiert werden. Verwenden Sie zum Aufrufen von Orchestrierungen in einer anderen App stattdessen das HTTP 202-Pollingmuster. Weitere Informationen finden Sie unter HTTP-Features.

In diesem Artikel:

Hinweis

In PowerShell werden Sub-Orchestrierungen nur im eigenständigen SDK unterstützt: AzureFunctions.PowerShell.Durable.SDK. Die Unterschiede zwischen dem eigenständigen SDK und dem integrierten Legacy-SDK finden Sie im Migrationshandbuch.

Definieren einer untergeordneten Orchestrierung

Im folgenden Beispiel wird ein IoT-Szenario veranschaulicht, in dem mehrere Geräte eingerichtet werden müssen. Die Funktion stellt den Setupworkflow dar, der für jedes Gerät ausgeführt wird:

Isoliertes Arbeitsmodell
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: ...
}

In-Prozess-Modell
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;
    }
}

Diese Orchestratorfunktion kann eigenständig für die einmalige Einrichtung eines Geräts ausgeführt werden, oder ein übergeordneter Orchestrator kann sie mithilfe der call-sub-orchestrator-API als untergeordnete Orchestrierung einplanen.

Paralleles Ausführen untergeordneter Orchestrierungen

Das folgende Beispiel zeigt einen übergeordneten Orchestrator, der mehrere untergeordnete Orchestrierungen parallel auffächert. In einigen Sprachen wird eine deterministische untergeordnete Instanz-ID verwendet (abgeleitet von der Instanz-ID des übergeordneten Elements plus Index), um doppelte untergeordnete Orchestrierungen während der Wiedergabe zu verhindern.

Isoliertes Arbeitsmodell
[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);

    // ...
}

In-Prozess-Modell
[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);

    // ...
}

Nächste Schritte

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;
    }
}

Nächste Schritte