Orchestrazioni secondarie

Le funzioni di orchestrazione possono chiamare altre funzioni di orchestrazione come sotto-orchestrazioni. Una sub-orchestrazione viene eseguita come figlio dell'orchestratore chiamante (padre) e si comporta come un'attività dal punto di vista del chiamante: può restituire un valore, sollevare eccezioni intercettate dal padre e supportare i tentativi automatici.

Quando usare le orchestrazioni secondarie

Usare le orchestrazioni secondarie quando è necessario:

  • Comporre blocchi costitutivi riutilizzabili del flusso di lavoro: Estrarre un flusso di lavoro in più passaggi nel proprio orchestratore in modo che più orchestrazioni principali possano chiamarlo.
  • Eseguire le orchestrazioni in parallelo: pianificare molte istanze dello stesso orchestratore contemporaneamente e attendere il completamento di tutte.
  • Organizzare flussi di lavoro complessi: Suddividere un'orchestrazione di grandi dimensioni in parti denominate testabili anziché una singola funzione lunga.

Annotazioni

Le orchestrazioni secondarie devono essere definite nella stessa app dell'orchestrazione padre. Per chiamare le orchestrazioni in un'app diversa, usare invece il modello di polling HTTP 202. Per altre informazioni, vedere Funzionalità HTTP.

Contenuto dell'articolo:

Annotazioni

In PowerShell le orchestrazioni secondarie sono supportate solo nell'SDK autonomo: AzureFunctions.PowerShell.Durable.SDK. Per le differenze tra l'SDK autonomo e l'SDK predefinito legacy, vedere la guida alla migrazione.

Definire un'orchestrazione secondaria

L'esempio seguente illustra uno scenario IoT in cui è necessario configurare più dispositivi. La funzione rappresenta il flusso di lavoro di installazione eseguito per ogni dispositivo:

Modello di lavoro isolato
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: ...
}

Modello in-process
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;
    }
}

Questa funzione dell'agente di orchestrazione può essere eseguita in modalità autonoma per la configurazione di un dispositivo occasionale oppure un agente di orchestrazione padre può pianificarla come sotto orchestrazione usando l'API call-sub-orchestrator .

Eseguire sotto-orchestrazioni in parallelo

L'esempio seguente mostra un orchestratore padre che distribuisce più sotto-orchestrazioni in parallelo. Alcuni linguaggi utilizzano un ID deterministico per le istanze secondarie (derivato dall'ID dell'istanza del padre più un indice) per impedire duplicazioni di orchestrazioni nella fase di ripetizione.

Modello di lavoro isolato
[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);

    // ...
}

Modello in-process
[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);

    // ...
}

Passaggi successivi

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

Passaggi successivi