Suborquestrações

As funções de orquestrador podem chamar outras funções de orquestrador como suborquestrações. Uma suborquestração executa-se como filha do orquestrador de chamada (pai) e comporta-se como uma atividade do ponto de vista do orquestrador de chamada: pode retornar um valor, lançar exceções capturadas pelo orquestrador pai e suportar retentativas automáticas.

Quando usar suborquestrações

Use suborquestrações quando precisar:

  • Construir blocos de construção de fluxo de trabalho reutilizáveis: Extrair um fluxo de trabalho multietapa num orquestrador separado para que múltiplas orquestrações principais o possam chamar.
  • Distribua orquestrações em paralelo: Agende várias instâncias do mesmo orquestrador simultaneamente e aguarde que todas terminem.
  • Organize fluxos de trabalho complexos: Divide uma orquestração grande em peças nomeadas e testáveis em vez de uma única função longa.

Observação

As suborquestrações devem ser definidas na mesma aplicação que a orquestração principal. Para chamar orquestrações numa aplicação diferente, use o padrão de sondagem HTTP 202 em vez disso. Para mais informações, veja funcionalidades HTTP.

Neste artigo:

Observação

No PowerShell, as suborquestrações são suportadas apenas no SDK autónomo: AzureFunctions.PowerShell.Durable.SDK. Para as diferenças entre o SDK autónomo e o SDK incorporado legado, consulte o guia de migração.

Defina uma suborquestração

O exemplo seguinte ilustra um cenário de IoT em que vários dispositivos precisam de ser configurados. A função representa o fluxo de trabalho de configuração que é executado para cada dispositivo:

Modelo de trabalhador isolado
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 em processo
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 função do orquestrador pode funcionar de forma autónoma para configuração pontual de dispositivos, ou um orquestrador pai pode agendá-la como uma sub-orquestração usando a API de chamada de sub-orquestrador .

Executar suborquestrações em paralelo

O exemplo seguinte mostra um orquestrador pai que distribui múltiplas suborquestrações em paralelo. Algumas linguagens usam um ID de instância filho determinístico (derivado do ID de instância do pai mais um índice) para evitar suborquestrações duplicadas durante a reprodução.

Modelo de trabalhador isolado
[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 em processo
[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);

    // ...
}

Passos seguintes

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

Passos seguintes