Chaînage de fonctions dans Fonctions durables - Exemple de séquence Hello
Article
Un chaînage de fonctions fait référence au modèle d’exécution d’une séquence de fonctions dans un ordre particulier. La sortie d’une fonction doit souvent être appliquée à l’entrée d’une autre fonction. Cet article décrit la séquence de chaînage que vous créez lorsque vous suivez le guide de démarrage rapide de Durable Functions (C#, JavaScript, TypeScript, Python, PowerShell ou Java). Pour plus d’informations sur Durable Functions, consultez Vue d’ensemble de Durable Functions.
La version 4 du modèle de programmation Node.js pour Azure Functions est en disponibilité générale. Le nouveau modèle v4 est conçu pour offrir une expérience plus flexible et intuitive pour les développeurs JavaScript et TypeScript. En savoir plus sur les différences entre v3 et v4 dans le guide de migration.
Dans les extraits de code suivants, JavaScript (PM4) désigne le modèle de programmation V4, la nouvelle expérience.
Les fonctions
Cet article explique les fonctions suivantes dans l’exemple d’application :
E1_HelloSequence: Une fonction d’orchestrateur qui appelle E1_SayHello plusieurs fois dans une séquence. Il stocke les sorties à partir des appels de E1_SayHello et enregistre les résultats.
E1_SayHello: Une fonction d’activité qui fait précéder une chaîne de « Hello ».
HttpStart : Une fonction client durable déclenchée par HTTP qui démarre une instance de l’orchestrateur.
Toutes les fonctions d’orchestration C# doivent avoir un paramètre de type DurableOrchestrationContext, qui existe dans l’assembly Microsoft.Azure.WebJobs.Extensions.DurableTask. Cet objet de contexte vous permet d’appeler d’autres fonctions d’activité et de passer les paramètres d’entrée à l’aide de sa méthode CallActivityAsync.
Le code appelle trois fois E1_SayHello en séquence avec des valeurs de paramètre différentes. La valeur renvoyée de chaque appel est ajoutée à la liste outputs, qui est retournée à la fin de la fonction.
function.json
Si vous utilisez Visual Studio Code ou le portail Azure pour le développement, voici le contenu du fichier function.json pour la fonction d’orchestrateur. La plupart des fichiers function.json d’orchestrateur ressemblent presque exactement à cela.
Le point essentiel est le type de liaison orchestrationTrigger. Toutes les fonctions d’orchestrateur doivent utiliser ce type de déclencheur.
Avertissement
Pour respecter la règle « Aucune E/S » des fonctions d’orchestrateur, n’utilisez aucune liaison d’entrée ou de sortie lors de l’utilisation de la liaison de déclenchement orchestrationTrigger. Si d’autres liaisons d’entrée ou de sortie sont nécessaires, elles doivent plutôt être utilisées dans le contexte des fonctions activityTrigger, qui sont appelées par l’orchestrateur. Pour plus d’informations, consultez l’article Contraintes du code des fonctions d’orchestrateur.
Toutes les fonctions d’orchestration JavaScript doivent inclure le module durable-functions. Il s’agit d’une bibliothèque qui vous permet d’écrire des fonctions Durable Functions en JavaScript. Il existe trois différences importantes entre une fonction d’orchestrateur et les autres fonctions JavaScript :
La fonction est encapsulée dans un appel à la méthode orchestrator du module durable-functions (ici df).
La fonction doit être synchrone. Parce que la méthode « orchestrator » traite l’appel final à « context.done », la fonction doit simplement retourner un résultat (« return »).
L’objet context contient un objet de contexte d’orchestration durable df qui vous permet d’appeler d’autres fonctions d’activité et de passer des paramètres d’entrée à l’aide de sa méthode callActivity. Le code appelle E1_SayHello trois fois à la suite avec différentes valeurs de paramètre, en se servant de yield pour indiquer que l’exécution doit attendre les appels de fonction d’activité asynchrones à renvoyer. La valeur renvoyée de chaque appel est ajoutée au tableau outputs qui est retourné à la fin de l’exécution de la fonction.
Toutes les fonctions d’orchestration JavaScript doivent inclure le module durable-functions. Ce module vous permet d’écrire des fonctions Durable Functions en JavaScript. Pour utiliser le modèle de programmation de nœud V4, vous devez installer la préversion v3.x de durable-functions.
Il existe deux différences importantes entre une fonction d’orchestrateur et les autres fonctions JavaScript :
La fonction doit être synchrone. La fonction doit simplement « retourner ».
L’objet context contient un objet de contexte d’orchestration durable df qui vous permet d’appeler d’autres fonctions d’activité et de passer des paramètres d’entrée à l’aide de sa méthode callActivity. Le code appelle sayHello trois fois à la suite avec différentes valeurs de paramètre, en se servant de yield pour indiquer que l’exécution doit attendre les appels de fonction d’activité asynchrones à renvoyer. La valeur renvoyée de chaque appel est ajoutée au tableau outputs qui est retourné à la fin de l’exécution de la fonction.
Notes
Les fonctions Durable Functions Python sont disponibles uniquement pour le runtime de Functions 3.0.
function.json
Si vous utilisez Visual Studio Code ou le portail Azure pour le développement, voici le contenu du fichier function.json pour la fonction d’orchestrateur. La plupart des fichiers function.json d’orchestrateur ressemblent presque exactement à cela.
Le point essentiel est le type de liaison orchestrationTrigger. Toutes les fonctions d’orchestrateur doivent utiliser ce type de déclencheur.
Avertissement
Pour respecter la règle « Aucune E/S » des fonctions d’orchestrateur, n’utilisez aucune liaison d’entrée ou de sortie lors de l’utilisation de la liaison de déclenchement orchestrationTrigger. Si d’autres liaisons d’entrée ou de sortie sont nécessaires, elles doivent plutôt être utilisées dans le contexte des fonctions activityTrigger, qui sont appelées par l’orchestrateur. Pour plus d’informations, consultez l’article Contraintes du code des fonctions d’orchestrateur.
Toutes les fonctions d’orchestration Python doivent inclure le package durable-functions. Il s’agit d’une bibliothèque qui vous permet d’écrire des fonctions Durable Functions en Python. Il existe deux différences importantes entre une fonction d’orchestrateur et les autres fonctions Python :
Le fichier doit enregistrer la fonction d’orchestrateur en tant qu’orchestrateur en indiquant main = df.Orchestrator.create(<orchestrator function name>) à la fin du fichier. Cela permet de le distinguer des autres fonctions d’aide déclarées dans le fichier.
Cet objet context vous permet d’appeler d’autres fonctions d’activité et de transmettre les paramètres d’entrée à l’aide de sa méthode call_activity. Le code appelle E1_SayHello trois fois à la suite avec différentes valeurs de paramètre, en se servant de yield pour indiquer que l’exécution doit attendre les appels de fonction d’activité asynchrones à renvoyer. La valeur renvoyée de chaque appel est retournée à la fin de la fonction.
[FunctionName("E1_SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext context)
{
string name = context.GetInput<string>();
return $"Hello {name}!";
}
Les activités utilisent l’attribut ActivityTrigger. Utilisez la valeur IDurableActivityContext fournie pour effectuer des actions liées à l’activité, telles que l’accès à la valeur d’entrée à l’aide de GetInput<T>.
L’implémentation de E1_SayHello est une opération de mise en forme de chaîne relativement simple.
Au lieu de lier à une valeur IDurableActivityContext, vous pouvez établir une liaison directe au type passé dans la fonction d’activité. Par exemple :
Le fichier function.json pour la fonction de l’activité E1_SayHello est similaire à celle de E1_HelloSequence sauf qu’elle utilise un type de liaison activityTrigger à la place d’un type de liaison orchestrationTrigger.
Toutes les fonctions d’activité appelées par une fonction d’orchestration doivent utiliser la liaison activityTrigger.
L’implémentation de E1_SayHello est une opération de mise en forme de chaîne relativement simple.
E1_SayHello/index.js
module.exports = function (context) {
context.done(null, `Hello ${context.bindings.name}!`);
};
Contrairement à la fonction d’orchestration, une fonction d’activité ne nécessite aucune configuration particulière. L’entrée transmise par la fonction d’orchestrateur se trouve sur l’objet context.bindings sous le nom de la liaison activityTrigger, ici context.bindings.name. Le nom de la liaison peut être défini en tant que paramètre de la fonction exportée et accessible directement, ce que fait l’exemple de code.
L’implémentation de sayHello est une opération de mise en forme de chaîne relativement simple.
Contrairement à la fonction d’orchestration, une fonction d’activité ne nécessite aucune configuration particulière. L’entrée qui lui est transmise par la fonction d’orchestrateur est le premier argument de la fonction. Le deuxième argument est le contexte d’appel, qui n’est pas utilisé dans cet exemple.
E1_SayHello/function.json
Le fichier function.json pour la fonction de l’activité E1_SayHello est similaire à celle de E1_HelloSequence sauf qu’elle utilise un type de liaison activityTrigger à la place d’un type de liaison orchestrationTrigger.
Contrairement à la fonction d’orchestrateur, une fonction d’activité ne nécessite aucune configuration particulière. L’entrée qui lui est transmise par la fonction d’orchestrateur est directement accessible en tant que paramètre de la fonction.
Fonction cliente HttpStart
Vous pouvez démarrer une instance de la fonction d’orchestrateur à l’aide d’une fonction cliente. Vous allez utiliser la fonction déclenchée par HTTP HttpStart pour démarrer des instances de E1_HelloSequence.
public static class HttpStart
{
[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
[DurableClient] IDurableClient starter,
string functionName,
ILogger log)
{
// Function input comes from the request content.
object eventData = await req.Content.ReadAsAsync<object>();
string instanceId = await starter.StartNewAsync(functionName, eventData);
log.LogInformation($"Started orchestration with ID = '{instanceId}'.");
return starter.CreateCheckStatusResponse(req, instanceId);
}
}
Pour interagir avec des orchestrateurs, la fonction doit inclure une liaison d’entrée DurableClient. Vous utilisez le client pour démarrer une orchestration. Il peut également vous aider à retourner une réponse HTTP contenant des URL pour vérifier l’état de la nouvelle orchestration.
Utilisez df.getClient pour obtenir un objet DurableOrchestrationClient. Vous utilisez le client pour démarrer une orchestration. Il peut également vous aider à retourner une réponse HTTP contenant des URL pour vérifier l’état de la nouvelle orchestration.
Pour gérer les orchestrateurs et interagir avec eux, la fonction a besoin d’une liaison d’entrée durableClient. Cette liaison doit être spécifiée dans l’argument extraInputs lors de l’inscription de la fonction. Vous pouvez obtenir une entrée durableClient en appelant df.input.durableClient().
Utilisez df.getClient pour obtenir un objet DurableClient. Vous utilisez le client pour démarrer une orchestration. Il peut également vous aider à retourner une réponse HTTP contenant des URL pour vérifier l’état de la nouvelle orchestration.
Pour interagir avec des orchestrateurs, la fonction doit inclure une liaison d’entrée durableClient.
HttpStart/__init__.py
import logging
import azure.functions as func
import azure.durable_functions as df
async def main(req: func.HttpRequest, starter: str) -> func.HttpResponse:
client = df.DurableOrchestrationClient(starter)
instance_id = await client.start_new(req.route_params["functionName"], None, None)
logging.info(f"Started orchestration with ID = '{instance_id}'.")
return client.create_check_status_response(req, instance_id)
Utilisez le DurableOrchestrationClient pour obtenir un client Durable Functions. Vous utilisez le client pour démarrer une orchestration. Il peut également vous aider à retourner une réponse HTTP contenant des URL pour vérifier l’état de la nouvelle orchestration.
Exécution de l'exemple
Pour exécuter l’orchestration E1_HelloSequence, envoyez la requête HTTP POST suivante à la fonction HttpStart.
POST http://{host}/orchestrators/E1_HelloSequence
Notes
L’extrait de code HTTP précédent suppose qu’il existe une entrée dans le fichier host.json, qui supprime le préfixe api/ par défaut de toutes les URL de fonctions de déclencheur HTTP. Le balisage pour cette configuration figure dans le fichier host.json dans les exemples.
Par exemple, si vous exécutez l’exemple dans une application de fonction nommée « myfunctionapp », remplacez « {hôte} » par « myfunctionapp.azurewebsites.net ».
Le résultat est une réponse HTTP 202, comme celle-ci (ajustée par souci de concision) :
À ce stade, l’orchestration est mise en file d’attente et commence à s’exécuter immédiatement. L’URL dans l’en-tête Location peut être utilisée pour vérifier l’état de l’exécution.
GET http://{host}/runtime/webhooks/durabletask/instances/96924899c16d43b08a536de376ac786b?taskHub=DurableFunctionsHub&connection=Storage&code={systemKey}
Le résultat est l'état de l'orchestration. Elle s’exécute et se termine rapidement, vous voyez donc le résultat dans l’état Terminé avec une réponse qui ressemble à ceci (ajustée par souci de concision) :
Comme vous pouvez le voir, le runtimeStatus de l’instance est Terminé et le output contient le résultat sérialisé en JSON de l’exécution de la fonction d’orchestration.
Notes
Vous pouvez implémenter une logique de démarrage similaire pour d’autres types de déclenchement, comme queueTrigger, eventHubTrigger, ou timerTrigger.
Examinez les journaux d’activité d’exécution de fonction. La fonction E1_HelloSequence a démarré et s’est terminée plusieurs fois en raison du comportement de relecture décrit dans la rubrique sur la fiabilité de l’orchestration. En revanche, il n’y a eu que trois exécutions de E1_SayHello étant donné que les exécutions de la fonction ne sont pas relues.
Étapes suivantes
Cet exemple a illustré une orchestration simple de chaînage de fonction. L’exemple suivant montre comment implémenter le modèle fan-out/fan-in.