Underorkestreringar

Orchestrator-funktioner kan anropa andra orkestreringsfunktioner som underorkestreringar. En underordnad orkestrering körs som en del av den anropande (överordnade) orkestratorn och fungerar ur anroparens perspektiv som en aktivitet: den kan returnera ett värde, utlösa undantag som fångas av den överordnade och stödja automatiskt återförsök.

När du ska använda underorkestreringar

Använd underorkestreringar när du behöver:

  • Skapa återanvändbara byggblock för arbetsflöden: Extrahera ett arbetsflöde i flera steg till en egen orkestrerare så att flera överordnade orkestreringar kan anropa det.
  • Distribuera orkestreringar parallellt: Schemalägg många instanser av samma orkestrator samtidigt och vänta tills alla har slutförts.
  • Organisera komplexa arbetsflöden: Dela upp en stor orkestrering i namngivna, testbara bitar i stället för en enda lång funktion.

Anmärkning

Underorkestreringar måste definieras i samma app som den överordnade orkestreringen. Om du vill anropa orkestreringar i en annan app använder du HTTP 202-avsökningsmönstret i stället. Mer information finns i HTTP-funktioner.

I den här artikeln:

Anmärkning

I PowerShell stöds underorkestreringar endast i fristående SDK: AzureFunctions.PowerShell.Durable.SDK. Skillnaderna mellan fristående SDK och den äldre inbyggda SDK:t finns i migreringsguiden.

Definiera en underorkestrering

I följande exempel visas ett IoT-scenario där flera enheter måste konfigureras. Funktionen representerar det installationsarbetsflöde som körs för varje enhet:

Isolerad arbetsmodell
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: ...
}

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

Den här orkestreringsfunktionen kan köras fristående för enstaka enhetskonfiguration, eller så kan en överordnad orkestrerare schemalägga den som en underorkestrering med api:et call-sub-orchestrator .

Köra underorkestreringar parallellt

I följande exempel visas en överordnad orkestrerare som fläktar ut flera underorkestreringar parallellt. Vissa språk använder ett deterministiskt underordnat instans-ID (härlett från det överordnade instans-ID:t plus ett index) för att förhindra duplicerade underorkestreringar under återspelning.

Isolerad arbetsmodell
[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);

    // ...
}

Processmodell
[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ästa steg

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ästa steg