Suborchestrierungen

Orchestratorfunktionen können andere Orchestratorfunktionen als Sub-Orchestrierungen aufrufen. Eine Suborchestrierung 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, eine Ausnahme auslösen, die vom übergeordneten Element abgefangen wird, und den automatischen Retry 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.
  • Parallele Fanout-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 Unter-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 das einmalige Setup eines Geräts ausgeführt werden, oder ein übergeordneter Orchestrator kann sie mithilfe der CALL-SUB-ORCHESTRATOR API als Unter-Orchestrierung einplanen.

Paralleles Ausführen von Unter-Orchestrierungen

Das folgende Beispiel zeigt einen übergeordneten Orchestrator, der mehrere Unter-Orchestrierungen parallel ausfächert. In einigen Sprachen wird eine deterministische untergeordnete Instanz-ID verwendet, die von der Instanz-ID des übergeordneten Elements plus eines Indexes abgeleitet ist, um doppelte Sub-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