Sub-orquestrações

As funções orquestradoras podem chamar outras funções orquestradoras como suborquestrações. Uma sub-orquestração é executada como um subprocesso do orquestrador de chamada (pai) e se comporta como uma atividade do ponto de vista do chamador: pode retornar um valor, lançar exceções capturadas pelo pai e oferecer suporte à repetição automática.

Quando usar sub-orquestrações

Use suborquestrações quando necessário:

  • Criar blocos de construção de workflow reutilizáveis: Extraia um workflow multi-etapas para um orquestrador dedicado, permitindo que várias orquestrações principais possam chamá-lo.
  • Abane orquestrações em paralelo: Agende muitas instâncias do mesmo orquestrador simultaneamente e aguarde até que todas elas sejam concluídas.
  • Organizar fluxos de trabalho complexos: Divida um grande processo de orquestração em partes nomeadas e testáveis em vez de uma única função longa.

Observação

As sub-orquestrações devem ser definidas no mesmo aplicativo que a orquestração pai. Para chamar orquestrações em um aplicativo diferente, use o padrão de sondagem HTTP 202. Para obter mais informações, consulte os recursos HTTP.

Neste artigo:

Observação

No PowerShell, as sub-orquestrações têm suporte apenas no SDK autônomo: AzureFunctions.PowerShell.Durable.SDK. Para obter as diferenças entre o SDK autônomo e o SDK interno herdado, consulte o guia de migração.

Definir uma sub-orquestração

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

Modelo de trabalho 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 de orquestrador pode ser executada de forma autônoma para configuração única de dispositivos ou um orquestrador pai pode agendá-la como uma sub-orquestração usando a API call-sub-orchestrator.

Executar sub-orquestrações em paralelo

O exemplo a seguir mostra um orquestrador principal que distribui várias sub-orquestrações em paralelo. Algumas linguagens usam uma ID de instância filho determinística (derivada da ID da instância do pai mais um índice) para evitar sub-orquestrações duplicadas na reexecução.

Modelo de trabalho 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);

    // ...
}

Próximas Etapas 

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

Próximas Etapas