Sub-orquestrações

As funções do Orchestrator podem chamar outras funções do Orchestrator como sub-orquestrações. Uma sub-orquestração é executada como uma instância filha do orquestrador chamador (pai) e, do ponto de vista do chamador, comporta-se como uma atividade: ela pode retornar um valor, lançar exceções capturadas pelo pai e oferecer suporte a nova tentativa automática.

Quando usar sub-orquestrações

Use sub-orquestrações quando for necessário:

  • Crie blocos de construção reutilizáveis para fluxos de trabalho: extraia um fluxo de trabalho de várias etapas para um orquestrador próprio, de modo que várias orquestrações pai possam chamá-lo.
  • Executar orquestrações em paralelo: agendar várias instâncias do mesmo orquestrador simultaneamente e aguardar que todas 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 polling 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 pai que distribui várias suborquestrações em paralelo. Algumas linguagens utilizam um ID de instância filha determinístico (derivado do ID de instância do pai mais um índice) para evitar a duplicação de sub-orquestrações durante a reproduçã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