Sub-orquestaciones

Las funciones de orquestación pueden llamar a otras funciones de orquestación como suborquestaciones. Una suborquestación se ejecuta como una entidad secundaria de la orquestación que la invoca (orquestación principal) y se comporta como una actividad desde la perspectiva del llamador: puede devolver un valor y generar excepciones que son capturadas por la orquestación principal y admitir el reintento automático.

Cuándo usar suborquestaciones

Utilice suborquestaciones cuando necesite:

  • Crear bloques de creación de flujos de trabajo reutilizables: Extraiga un flujo de trabajo de varios pasos en su propio orquestador para que varias orquestaciones primarias puedan llamarla.
  • Distribución ramificada de orquestaciones en paralelo: Programe muchas instancias del mismo orquestador simultáneamente y espere a que finalicen todas ellas.
  • Organizar flujos de trabajo complejos: Divida una orquestación grande en partes con nombre y que se puedan probar en lugar de una sola función larga.

Nota:

Las suborquestaciones deben definirse en la misma aplicación que la orquestación primaria. Para llamar a orquestaciones en otra aplicación, use el patrón de sondeo HTTP 202 en su lugar. Para obtener más información, consulte Características HTTP.

En este artículo:

Nota:

En PowerShell, las sub-orquestaciones solo se admiten en el SDK independiente: AzureFunctions.PowerShell.Durable.SDK. Para conocer las diferencias entre el SDK independiente y el SDK integrado heredado, consulte la guía de migración.

Definición de una suborquestación

En el ejemplo siguiente se muestra un escenario de IoT en el que es necesario configurar varios dispositivos. La función representa el flujo de trabajo de instalación que se ejecuta para cada dispositivo:

Modelo de trabajo aislado
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: ...
}

Modelo en proceso
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;
    }
}

Esta función de orquestador puede ejecutarse de forma independiente para la configuración de un dispositivo único o un orquestador primario puede programarla como una sub-orquestación mediante la API call-sub-orchestrator .

Ejecución de suborquestaciones en paralelo

En el siguiente ejemplo se muestra un orquestador primario que distribuye de manera ramificada varias suborquestaciones en paralelo. Algunos lenguajes usan un identificador de instancia secundario determinista (derivado del identificador de instancia del elemento más un índice), para evitar las suborquestaciones duplicadas durante la repetición.

Modelo de trabajo aislado
[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);

    // ...
}

Modelo en proceso
[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);

    // ...
}

Pasos siguientes

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

Pasos siguientes