Encadenamiento de funciones en Durable Functions: Hello Sequence de ejemplo
Artículo
El encadenamiento de funciones hace referencia al patrón de ejecución de una secuencia de funciones en un orden concreto. A menudo la salida de una función tiene que aplicarse a la entrada de otra función. En este artículo se describe la secuencia de encadenamiento que se crea al completar el inicio rápido de Durable Functions (C#, JavaScript, TypeScript, Python, PowerShell o Java). Para más información sobre Durable Functions, consulte Durable Functions overview (Información general de Durable Functions).
La versión 4 del modelo de programación de Node.js para Azure Functions está disponible de forma general. El nuevo modelo v4 está diseñado para que los desarrolladores de JavaScript y TypeScript tengan una experiencia más flexible e intuitiva. Obtenga más información sobre las diferencias entre v3 y v4 en la guía de migración.
En los siguientes fragmentos de código, JavaScript (PM4) denota el modelo de programación V4, la nueva experiencia.
Funciones
En este artículo se explican las funciones siguientes en la aplicación de ejemplo:
E1_HelloSequence: una función de orquestador que llama a E1_SayHello varias veces en una secuencia. Almacena las salidas de las llamadas de E1_SayHello y registra los resultados.
Todas las funciones de orquestación de C# deben tener un parámetro de tipo DurableOrchestrationContext, que existe en el ensamblado Microsoft.Azure.WebJobs.Extensions.DurableTask. Este objeto de contexto le permite llamar a otras funciones de actividad y pasar parámetros de entrada con su método CallActivityAsync.
El código llama a E1_SayHello tres veces en secuencia con distintos valores de parámetro. El valor devuelto de cada llamada se agrega a la lista outputs, que se devuelve al final de la función.
function.json
Si utiliza Visual Studio Code o Azure Portal para el desarrollo, aquí tiene el contenido del archivo function.json para la función de orquestador. La mayoría de los archivos function.json de orquestador presentan un aspecto prácticamente idéntico a este.
Lo importante es el tipo de enlace orchestrationTrigger. Todas las funciones de orquestador deben usar este tipo de desencadenador.
Advertencia
Para cumplir la regla de "ninguna E/S" de las funciones de orquestador, no use ningún enlace de entrada o salida al utilizar el enlace de desencadenador orchestrationTrigger. Si se necesitan otros enlaces de entrada o salida, deberían utilizarse en el contexto de funciones activityTrigger en su lugar, a las que llama el orquestador. Para más información, consulte el artículo sobre las restricciones de código de las funciones de orquestador.
index.js
La función de orquestador se muestra a continuación:
Todas las funciones de orquestación de JavaScript tienen que incluir el módulo durable-functions. Se trata de una biblioteca que le permite escribir Durable Functions en JavaScript. Hay tres diferencias importantes entre una función de orquestador y otras funciones de JavaScript:
La función se ajusta en una llamada al método orchestrator del módulo durable-functions (aquí df).
La función debe ser sincrónica. Dado que el método "orchestrator" se encarga de la llamada final a "context.done", la función debería simplemente devolver "return".
El objeto context contiene un objeto de contexto de orquestación df duradero que le permite llamar a otras funciones de actividad y pasar parámetros de entrada mediante su método callActivity. El código llama a E1_SayHello tres veces en secuencia con valores de parámetro diferentes, utilizando yield para indicar que la ejecución debe esperar en las llamadas de función de actividad asincrónica que se van a devolver. El valor devuelto de cada llamada se agrega a la matriz outputs, que se devuelve al final de la función.
Todas las funciones de orquestación de JavaScript tienen que incluir el módulo durable-functions. Este módulo le permite escribir Durable Functions en JavaScript. Para usar el modelo de programación de nodos V4, debe instalar la versión preliminar v3.x de durable-functions.
Hay dos diferencias importantes entre una función de orquestador y otras funciones de JavaScript:
La función debe ser sincrónica. La función simplemente debe "devolver".
El objeto context contiene un objeto de contexto de orquestación df duradero que le permite llamar a otras funciones de actividad y pasar parámetros de entrada mediante su método callActivity. El código llama a sayHello tres veces en secuencia con valores de parámetro diferentes, utilizando yield para indicar que la ejecución debe esperar en las llamadas de función de actividad asincrónica que se van a devolver. El valor devuelto de cada llamada se agrega a la matriz outputs, que se devuelve al final de la función.
Nota
Durable Functions de Python solo está disponible para el entorno de ejecución de Functions 3.0.
function.json
Si utiliza Visual Studio Code o Azure Portal para el desarrollo, aquí tiene el contenido del archivo function.json para la función de orquestador. La mayoría de los archivos function.json de orquestador presentan un aspecto prácticamente idéntico a este.
Lo importante es el tipo de enlace orchestrationTrigger. Todas las funciones de orquestador deben usar este tipo de desencadenador.
Advertencia
Para cumplir la regla de "ninguna E/S" de las funciones de orquestador, no use ningún enlace de entrada o salida al utilizar el enlace de desencadenador orchestrationTrigger. Si se necesitan otros enlaces de entrada o salida, deberían utilizarse en el contexto de funciones activityTrigger en su lugar, a las que llama el orquestador. Para más información, consulte el artículo sobre las restricciones de código de las funciones de orquestador.
__init__.py
La función de orquestador se muestra a continuación:
Todas las funciones de orquestación de Python tienen que incluir el paquete durable-functions. Se trata de una biblioteca que le permite escribir Durable Functions en Python. Hay dos diferencias importantes entre una función de orquestador y otras funciones de Python:
El archivo debe indicar main = df.Orchestrator.create(<orchestrator function name>) al final del archivo para registrar la función de orquestador como un orquestador. Esto ayuda a distinguirlo de otras funciones auxiliares que se declaran en el archivo.
El objeto context le permite llamar a otras funciones de actividad y pasar parámetros de entrada con su método call_activity. El código llama a E1_SayHello tres veces en secuencia con valores de parámetro diferentes, utilizando yield para indicar que la ejecución debe esperar en las llamadas de función de actividad asincrónica que se van a devolver. El valor devuelto de cada llamada se devuelve al final de la función.
[FunctionName("E1_SayHello")]
public static string SayHello([ActivityTrigger] IDurableActivityContext context)
{
string name = context.GetInput<string>();
return $"Hello {name}!";
}
Las actividades usan el atributo ActivityTrigger. Use el IDurableActivityContext proporcionado para realizar acciones relacionadas con la actividad, como el acceso al valor de entrada mediante GetInput<T>.
La implementación de E1_SayHello es una operación de formato de cadena relativamente sencilla.
En lugar de enlazar a un IDurableActivityContext, puede enlazar directamente con el tipo que se pasa a la función de actividad. Por ejemplo:
El archivo function.json para la función de actividad E1_SayHello es similar al de E1_HelloSequence salvo en que usa un tipo de enlace activityTrigger en lugar de un tipo de enlace orchestrationTrigger.
Todas las funciones de actividad a las que ha llamado una función de orquestación deben utilizar el enlace activityTrigger.
La implementación de E1_SayHello es una operación de formato de cadena relativamente sencilla.
E1_SayHello/index.js
module.exports = function (context) {
context.done(null, `Hello ${context.bindings.name}!`);
};
A diferencia de la función de orquestación, una función de actividad no necesita una configuración especial. La entrada que le pasa la función del orquestador se encuentra en el objeto context.bindings bajo el nombre del enlace activityTrigger, en este caso context.bindings.name. El nombre de enlace puede establecerse como un parámetro de la función exportada y se puede acceder a él directamente, que es lo que hace el código de ejemplo.
La implementación de sayHello es una operación de formato de cadena relativamente sencilla.
A diferencia de la función de orquestación, una función de actividad no necesita una configuración especial. La entrada que se le ha pasado a través de la función de orquestador es el primer argumento para la función. El segundo argumento es el contexto de invocación, que no se usa en este ejemplo.
E1_SayHello/function.json
El archivo function.json para la función de actividad E1_SayHello es similar al de E1_HelloSequence salvo en que usa un tipo de enlace activityTrigger en lugar de un tipo de enlace orchestrationTrigger.
A diferencia de una función de orquestador, una función de actividad no necesita una configuración especial. La entrada que se le ha pasado a través de la función de orquestador es directamente accesible como parámetro para la función.
Función de cliente HttpStart
Puede iniciar una instancia de la función de orquestador mediante una función de cliente. Usará la función desencadenada por HTTP HttpStartpara iniciar instancias 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);
}
}
Para interactuar con los orquestadores, la función tiene que incluir un enlace de entrada DurableClient. El cliente se utiliza para iniciar una orquestación. También puede ayudarle a devolver una respuesta HTTP que contiene las direcciones URL para comprobar el estado de la nueva orquestación.
Para obtener un objeto DurableOrchestrationClient, use df.getClient. El cliente se utiliza para iniciar una orquestación. También puede ayudarle a devolver una respuesta HTTP que contiene las direcciones URL para comprobar el estado de la nueva orquestación.
Para administrar e interactuar con los orquestadores, la función necesita un enlace de entrada durableClient. Este enlace debe especificarse en el argumento extraInputs al registrar la función. Se puede obtener una entrada durableClient llamando a df.input.durableClient().
Para obtener un objeto DurableClient, use df.getClient. El cliente se utiliza para iniciar una orquestación. También puede ayudarle a devolver una respuesta HTTP que contiene las direcciones URL para comprobar el estado de la nueva orquestación.
Para interactuar con los orquestadores, la función tiene que incluir un enlace de entrada 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)
Utilice el constructor DurableOrchestrationClient para obtener un cliente de Durable Functions. El cliente se utiliza para iniciar una orquestación. También puede ayudarle a devolver una respuesta HTTP que contiene las direcciones URL para comprobar el estado de la nueva orquestación.
Ejecución del ejemplo
Para ejecutar la orquestación de E1_HelloSequence, envíe la siguiente solicitud POST HTTP a la función HttpStart.
POST http://{host}/orchestrators/E1_HelloSequence
Nota
El fragmento de código HTTP anterior da por supuesto que hay una entrada en el archivo host.json que elimina el prefijo api/ predeterminado de todas las direcciones URL de las funciones de activación de HTTP. Puede encontrar el marcador para esta configuración en el archivo host.json en los ejemplos.
Por ejemplo, si ejecuta el ejemplo en una aplicación de función llamada "myfunctionapp", reemplace "{host}" por "myfunctionapp.azurewebsites.net".
El resultado es una respuesta HTTP 202, similar a la siguiente (acortada para simplificar):
En este punto, la orquestación se pone en cola y comienza a ejecutarse inmediatamente. La dirección URL en el encabezado Location puede usarse para comprobar el estado de la ejecución.
GET http://{host}/runtime/webhooks/durabletask/instances/96924899c16d43b08a536de376ac786b?taskHub=DurableFunctionsHub&connection=Storage&code={systemKey}
El resultado es el estado de la orquestación. Se ejecuta y se completa con rapidez, por lo que se muestra con el estado Completed (Completado) con una respuesta similar a la siguiente (acortada para simplificar):
Como puede ver, el valor de runtimeStatus de la instancia es Completed (Completado) y output contiene el resultado serializado con JSON de la ejecución de la función de orquestador.
Nota
Puede implementar una lógica de inicio similar para otros tipos de desencadenadores, como queueTrigger, eventHubTrigger o timerTrigger.
Observe los registros de ejecución de la función. La función E1_HelloSequence se ha iniciado y completado varias veces debido al comportamiento de reproducción descrito en el tema sobre la confiabilidad de la orquestación. Por otro lado, solo ha habido tres de ejecuciones de E1_SayHello, puesto que esas ejecuciones de función no se reproducen.
Pasos siguientes
En este ejemplo se ha demostrado una orquestación de encadenamiento de función simple. En el ejemplo siguiente se muestra cómo implementar el de distribución ramificada de salida y entrada.