Sous-orchestrations

Les fonctions d’orchestrateur peuvent appeler d’autres fonctions d’orchestrateur en tant que sous-orchestrations. Une sous-orchestration fonctionne comme un processus enfant de l’orchestrateur parent et est perçue comme une activité du point de vue de ce dernier : elle peut retourner une valeur, déclencher des exceptions gérées par le parent et prendre en charge des mécanismes de nouvelle tentative automatique.

Quand utiliser des sous-orchestrations

Utilisez des sous-orchestrations lorsque vous devez :

  • Construisez des composants de workflow réutilisables : isolez un processus en plusieurs étapes dans un orchestrateur dédié afin qu’il puisse être invoqué par plusieurs orchestrations parentes.
  • Exécutez des orchestrations en parallèle : lancez simultanément plusieurs instances d’un même orchestrateur et attendez leur achèvement collectif.
  • Organiser des flux de travail complexes : Décomposez une grande orchestration en éléments nommés, testables au lieu d’une seule fonction longue.

Note

Les sous-orchestrations doivent être définies dans la même application que l’orchestration parente. Pour appeler des orchestrations dans une autre application, utilisez plutôt le modèle d’interrogation HTTP 202. Pour plus d’informations, consultez les fonctionnalités HTTP.

Contenu de cet article :

Note

Dans PowerShell, les sous-orchestrations sont prises en charge uniquement dans le Kit de développement logiciel (SDK) autonome : AzureFunctions.PowerShell.Durable.SDK. Pour connaître les différences entre le Kit de développement logiciel (SDK) autonome et le SDK intégré hérité, consultez le guide de migration.

Définir une sous-orchestration

L’exemple suivant illustre un scénario IoT où plusieurs appareils doivent être configurés. La fonction représente le flux de travail d’installation qui s’exécute pour chaque appareil :

Modèle de travailleur isolé
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: ...
}

Modèle 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;
    }
}

Cette fonction d'orchestrateur peut s'exécuter de manière autonome pour la configuration d'un appareil unique, ou un orchestrateur parent peut la planifier en tant que sous-orchestration à l'aide de l'API call-sub-orchestrator.

Exécuter des sous-orchestrations en parallèle

L’exemple suivant montre un orchestrateur principal qui répartit plusieurs sous-orchestrations en parallèle. Certaines langues utilisent un ID d’instance enfant déterministe (dérivé de l’ID d’instance du parent et d’un index) pour empêcher les sous-orchestrations en double lors de la relecture.

Modèle de travailleur isolé
[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);

    // ...
}

Modèle 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);

    // ...
}

Étapes suivantes

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

Étapes suivantes