What are triggers in Azure Functions?

Disparadores en Azure Functions: La Clave para Funciones Reactivas

hace 8 años

Valoración: 4.86 (4330 votos)

En el mundo del desarrollo serverless con Azure Functions, los disparadores juegan un papel fundamental. Son la chispa que enciende la ejecución de tu código, permitiendo que tus funciones respondan de manera automática a una variedad de eventos y servicios. Comprender qué son y cómo funcionan los disparadores es esencial para aprovechar al máximo el potencial de Azure Functions.

What are triggers in Azure Functions?
In this article A trigger defines how a function is invoked and a function must have exactly one trigger. Triggers can also pass data into your function, as you would with method calls. Oct 28, 2024
Índice de Contenido

¿Qué son Exactamente los Disparadores en Azure Functions?

Un disparador es, en esencia, un detector de eventos. Define cómo se invoca una función. Piensa en él como un vigilante que está constantemente observando un determinado evento o servicio. Cuando ese evento ocurre, el disparador 'activa' tu función, indicándole que debe comenzar a ejecutarse. Cada función en Azure Functions debe tener exactamente un disparador. Esta unicidad garantiza que cada función tenga un punto de partida claro y bien definido.

Además de iniciar la ejecución, los disparadores también pueden pasar datos a tu función. Imagina que el disparador está observando una cola de mensajes. Cuando llega un nuevo mensaje, el disparador no solo activa la función, sino que también le entrega el contenido de ese mensaje para que la función pueda procesarlo. Esto es similar a cómo pasas argumentos a una función en la programación tradicional.

Disparadores vs. Enlaces: Entendiendo la Diferencia

Es común escuchar hablar de disparadores y enlaces (bindings) en Azure Functions, y aunque están relacionados, no son lo mismo. Mientras que un disparador *inicia* la función, los enlaces se encargan de la conexión declarativa de tu función con otros recursos.

Los enlaces pueden ser de dos tipos:

  • Enlaces de entrada (input bindings): Proporcionan datos a tu función, similar a como lo hace un disparador. De hecho, el disparador en sí mismo es un tipo especial de enlace de entrada.
  • Enlaces de salida (output bindings): Permiten escribir datos desde tu función hacia otros recursos.

Puedes combinar diferentes enlaces de entrada y salida para adaptar tu función a escenarios específicos. Los enlaces son opcionales, y una función puede tener uno o varios enlaces de entrada, salida, o incluso ninguno además del disparador.

Beneficios Clave de Utilizar Disparadores y Enlaces

La principal ventaja de utilizar disparadores y enlaces es que te permiten evitar la codificación manual del acceso a otros servicios. En lugar de escribir código complejo para conectarte a una cola de mensajes, a un almacenamiento de blobs o a una base de datos, simplemente defines un enlace. Azure Functions se encarga de la conexión y la gestión de datos.

Con disparadores y enlaces, tu función recibe los datos necesarios (por ejemplo, el contenido de un mensaje en cola) directamente como parámetros de la función. De manera similar, puedes enviar datos a otros servicios (por ejemplo, crear un nuevo mensaje en cola) utilizando el valor de retorno de la función o parámetros de salida específicos.

Ejemplos Prácticos de Escenarios con Disparadores y Enlaces

Para comprender mejor cómo funcionan en conjunto los disparadores y los enlaces, veamos algunos ejemplos de escenarios comunes:

EscenarioDisparadorEnlace de EntradaEnlace de Salida
Llega un nuevo mensaje a una cola y se ejecuta una función para escribir en otra cola.Cola*NingunoCola*
Un trabajo programado lee contenido de Blob Storage y crea un nuevo documento en Azure Cosmos DB.Temporizador (Timer)Blob StorageAzure Cosmos DB
Event Grid se utiliza para leer una imagen de Blob Storage y un documento de Azure Cosmos DB para enviar un correo electrónico.Event GridBlob Storage y Azure Cosmos DBSendGrid

* Representa diferentes colas

Estos ejemplos ilustran la flexibilidad de Azure Functions. Puedes crear funciones que respondan a una amplia gama de eventos y que interactúen con diversos servicios de Azure sin necesidad de escribir código de conexión complejo.

Importante: Aunque los enlaces son la forma recomendada de interactuar con servicios de Azure, Azure Functions también te permite utilizar directamente los SDKs de Azure dentro de tu código. Esto te da aún más control, pero requiere una gestión manual de las conexiones y la autenticación.

Definición de Disparadores y Enlaces en Diferentes Lenguajes

La forma en que defines los disparadores y enlaces varía según el lenguaje de programación que utilices para tus Azure Functions. A continuación, veremos ejemplos para algunos de los lenguajes más populares.

C#

En C#, los disparadores y enlaces se configuran utilizando atributos de C# que decoran métodos y parámetros. La forma exacta de hacerlo puede variar ligeramente según el modelo de runtime de C# que utilices (modelo aislado o modelo en proceso).

Modelo de Trabajador Aislado de C#

En el modelo de trabajador aislado, el disparador HTTP (HttpTrigger) se define en el método Run de una función. El siguiente ejemplo muestra una función HttpExample que devuelve un objeto MultiResponse:

[Function("HttpExample")] public static MultiResponse Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req, FunctionContext executionContext) { // ... tu código de función ... } 

El objeto MultiResponse en este ejemplo define tanto la respuesta HTTP como un enlace de salida a una cola de almacenamiento (QueueOutput):

public class MultiResponse { [QueueOutput("outqueue",Connection = "AzureWebJobsStorage")] public string[] Messages { get; set; } public HttpResponseData HttpResponse { get; set; } } 

Modelo en Proceso de C#

En el modelo en proceso, el disparador HTTP (HttpTrigger) también se define en el método Run. El enlace de salida a la cola se configura con los atributos Queue y StorageAccount en el parámetro msg:

[FunctionName("HttpExample")] public static async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, [Queue("outqueue"),StorageAccount("AzureWebJobsStorage")] ICollector<string> msg, ILogger log) { // ... tu código de función ... } 

Java

Al igual que en C#, los disparadores y enlaces en Java se configuran mediante anotaciones en métodos y parámetros. El siguiente ejemplo muestra un disparador HTTP (@HttpTrigger) en el método run de una función HttpTriggerQueueOutput, que escribe en una cola de almacenamiento mediante la anotación @QueueOutput:

@FunctionName("HttpExample") public HttpResponseMessage run( @HttpTrigger( name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request, @QueueOutput( name = "msg", queueName = "outqueue", connection = "AzureWebJobsStorage") OutputBinding<String> msg, final ExecutionContext context) { context.getLogger().info("Java HTTP trigger processed a request."); // ... tu código de función ... } 

Node.js

La configuración de disparadores y enlaces en Node.js depende de la versión de Node.js para Functions que estés utilizando (v4 o v3). En la versión 4, se utilizan objetos exportados desde el módulo @azure/functions, mientras que en la versión 3 se configura en un archivo function.json específico de la función.

Node.js v4

const { app, output } = require('@azure/functions'); const queueOutput = output.storageQueue({ queueName: 'outqueue', connection: 'MyStorageConnectionAppSetting', }); app.http('httpTrigger1', { methods: ['GET', 'POST'], authLevel: 'anonymous', extraOutputs: [queueOutput], handler: async (request, context) => { const body = await request.text(); context.extraOutputs.set(queueOutput, body); return { body: 'Created queue item.' }; }, }); 

Node.js v3 (function.json)

{ "bindings": [ { "type": "httpTrigger", "direction": "in", "authLevel": "function", "name": "input" }, { "type": "http", "direction": "out", "name": "$return" }, { "type": "queue", "direction": "out", "name": "myQueueItem", "queueName": "outqueue", "connection": "MyStorageConnectionAppSetting" } ] } 

PowerShell (function.json)

{ "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "Request", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "Response" }, { "type": "queue", "direction": "out", "name": "msg", "queueName": "outqueue", "connection": "AzureWebJobsStorage" } ] } 

Python

La forma de definir funciones en Python también depende de la versión de Python para Functions (v2 o v1). En la versión 2, se utilizan decoradores directamente en el código, mientras que en la versión 1 se utiliza un archivo function.json.

Python v2

import azure.functions as func import logging app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS) @app.route(route="HttpExample") @app.queue_output(arg_name="msg", queue_name="outqueue", connection="AzureWebJobsStorage") def HttpExample(req: func.HttpRequest, msg: func.Out[func.QueueMessage]) -> func.HttpResponse: logging.info('Python HTTP trigger function processed a request.') # ... tu código de función ... 

Python v1 (function.json)

{ "bindings": [ { "authLevel": "function", "type": "httpTrigger", "direction": "in", "name": "Request", "methods": [ "get", "post" ] }, { "type": "http", "direction": "out", "name": "Response" }, { "type": "queue", "direction": "out", "name": "msg", "queueName": "outqueue", "connection": "AzureWebJobsStorage" } ] } 

Añadir Enlaces a una Función Existente

Puedes ampliar la funcionalidad de tus funciones conectándolas a otros servicios mediante enlaces de entrada o salida. Añadir un enlace es sencillo: basta con agregar las definiciones específicas del enlace a la configuración de tu función. Para aprender cómo hacerlo paso a paso, consulta la documentación de Azure Functions sobre cómo añadir enlaces a una función existente.

Why is Azure function not triggering?
If you find that the trigger didn't receive some changes, the most common scenario is that another Azure function is running. The other function might be deployed in Azure or a function might be running locally on a developer's machine with exactly the same configuration.

Azure Functions soporta múltiples enlaces, lo que te permite crear funciones complejas que interactúan con varios servicios simultáneamente. Por ejemplo, una función puede leer datos de una cola (enlace de entrada) y escribir resultados en una base de datos (enlace de salida) al mismo tiempo.

Enlaces Soportados en Azure Functions

Azure Functions ofrece una amplia gama de enlaces predefinidos para interactuar con diversos servicios de Azure y otros servicios de terceros. La disponibilidad de ciertos enlaces puede depender de la versión del runtime de Azure Functions que estés utilizando.

ServicioDisparadorEntradaSalidaEjemplos y Muestras
Blob StorageEnlace
Azure Cosmos DBEnlace
Azure Data ExplorerEnlace
Azure SQLEnlace
Event GridEnlace
Event Hubs
IoT Hub
HTTPEnlace
Queue storageEnlace
RabbitMQ
SendGrid
Service BusEnlace
SignalR
Table storage
TimerEnlace
TwilioEnlace

Nota: La disponibilidad de enlaces y sus versiones específicas pueden variar. Consulta la documentación oficial de Azure Functions para obtener la información más actualizada.

Ejemplos de Código de Enlaces

Para obtener ejemplos de código específicos para cada tipo de enlace, consulta la documentación de Azure Functions. Encontrarás ejemplos en diferentes lenguajes de programación que te mostrarán cómo trabajar con cada enlace en tus funciones.

Enlaces Personalizados

Si necesitas interactuar con un servicio que no tiene un enlace predefinido en Azure Functions, puedes crear tus propios enlaces personalizados. Estos enlaces deben desarrollarse en .NET, pero pueden ser utilizados desde cualquier lenguaje soportado por Azure Functions. Para más información sobre la creación de enlaces personalizados, consulta la documentación oficial.

Preguntas Frecuentes sobre Disparadores en Azure Functions

A continuación, respondemos algunas preguntas comunes relacionadas con los disparadores en Azure Functions, basadas en problemas típicos que pueden surgir al utilizarlos, especialmente con el disparador de Azure Cosmos DB.

Mi función de Azure falla con el mensaje de error "La colección 'nombre-de-colección' no existe"

Este error indica que una o ambas colecciones de Azure Cosmos DB necesarias para que el disparador funcione no existen o no son accesibles para la función de Azure. Las colecciones requeridas son la colección de origen (donde se producen los cambios que disparan la función) y la colección de concesiones (lease collection, utilizada para mantener el estado del disparador).

Solución:

  • Verifica el atributo Connection del disparador y asegúrate de que referencia a una configuración válida en tu aplicación de funciones de Azure. El valor no debe ser la cadena de conexión directamente, sino el nombre de la configuración.
  • Comprueba que los valores de databaseName y containerName existan en tu cuenta de Azure Cosmos DB y que coincidan con la colección de origen.
  • Si utilizas la sustitución automática de valores (patrones %nombreDeConfiguración%), verifica que el nombre de la configuración exista en tu aplicación de funciones.
  • Si no especificas un valor para LeaseContainerName/leaseContainerName, el valor predeterminado es leases. Asegúrate de que exista una colección con ese nombre para las concesiones.
  • Opcionalmente, puedes establecer el atributo CreateLeaseContainerIfNotExists en tu disparador a true para que la colección de concesiones se cree automáticamente si no existe.
  • Verifica la configuración del firewall de tu cuenta de Azure Cosmos DB para asegurarte de que no está bloqueando el acceso a la función de Azure.

Mis cambios tardan demasiado en ser recibidos por la función

Este problema puede tener varias causas:

Posibles causas y soluciones:

  • Ubicación de la función y la cuenta de Cosmos DB: Asegúrate de que tu función de Azure y tu cuenta de Azure Cosmos DB estén desplegadas en la misma región de Azure para minimizar la latencia de red.
  • Frecuencia de los cambios: Si los cambios en tu contenedor de Azure Cosmos DB son esporádicos, puede haber un retraso entre el momento en que se almacenan los cambios y el momento en que la función los recoge. Esto se debe a que el disparador verifica periódicamente si hay cambios. Puedes configurar el tiempo de espera entre verificaciones con la configuración FeedPollDelay/feedPollDelay (en milisegundos).
  • Limitación de velocidad en Cosmos DB: Verifica si tu contenedor de Azure Cosmos DB está siendo limitado por la tasa de solicitudes (rate-limited).
  • Ubicaciones preferidas: Utiliza el atributo PreferredLocations en tu disparador para especificar una lista de regiones de Azure preferidas para la conexión.
  • Tiempo de ejecución de la función: Si la función tarda mucho en ejecutarse, esto puede retrasar la recepción de nuevos cambios. Optimiza el código de tu función para reducir el tiempo de ejecución.
  • Capacidad de procesamiento del disparador: Si la velocidad de las operaciones en tu contenedor de Azure Cosmos DB es mayor que la velocidad de procesamiento de tu disparador, este se irá quedando rezagado.
  • Retrasos de red: Utiliza registros de depuración (Debug logs) para verificar si hay retrasos de red.

Algunos cambios se repiten en mi disparador

Es posible que recibas eventos para el mismo elemento varias veces. Esto puede ocurrir en los siguientes escenarios:

Posibles causas:

  • Fallos en la ejecución de la función: Si tu función falla durante la ejecución y las políticas de reintento están habilitadas, o si la ejecución excede el tiempo permitido, el mismo lote de cambios puede entregarse de nuevo a la función.
  • Balanceo de carga de concesiones: Cuando el número de instancias de la función aumenta o disminuye, el balanceo de carga de las concesiones puede provocar que el mismo lote de cambios se entregue a múltiples instancias de la función. Esto es un comportamiento transitorio esperado.
  • Actualizaciones del elemento: El change feed (fuente de cambios) puede contener múltiples operaciones para el mismo elemento si este se está actualizando con frecuencia. Puedes distinguir entre diferentes operaciones para el mismo elemento rastreando la propiedad _lsn para cada cambio.

Faltan algunos cambios en mi disparador

Si detectas que algunos cambios realizados en tu contenedor de Azure Cosmos DB no se están recogiendo por la función, considera lo siguiente:

Posibles causas y soluciones:

  • Registros habilitados: Asegúrate de tener los registros habilitados para verificar si se producen errores durante el procesamiento.
  • Medir en el punto de ingestión: Mide los cambios que se reciben en el punto de ingestión de la función, no en el destino final, para asegurarte de que el problema está en la recepción de cambios y no en el procesamiento posterior.
  • Errores en la función: Añade bloques try/catch en el código de tu función para detectar posibles errores durante el procesamiento de los cambios. Configura políticas de reintento en Azure Functions.
  • Clave de partición incorrecta en el destino: Si el destino es otro contenedor de Azure Cosmos DB, verifica que la definición de la clave de partición sea la misma en ambos contenedores.
  • Otra función en ejecución: Asegúrate de que no haya otra función de Azure (en Azure o localmente) con la misma configuración que esté "robando" parte de los cambios. Verifica el número de instancias de tu función y el número de propietarios de concesiones en la colección de concesiones. Utiliza un LeaseCollectionPrefix/leaseCollectionPrefix diferente para cada función o prueba con una nueva colección de concesiones.

Necesito reiniciar y reprocesar todos los elementos de mi contenedor desde el principio

Para reprocesar todos los elementos desde el inicio:

  1. Detén tu función de Azure si está en ejecución.
  2. Elimina los documentos de la colección de concesiones (o elimina y vuelve a crear la colección para que esté vacía).
  3. Establece el atributo StartFromBeginning del disparador CosmosDBTrigger en true.
  4. Reinicia la función de Azure.

Importante:StartFromBeginning = true solo funciona si no existen concesiones previas. Si ya existen concesiones, la función continuará leyendo desde el último punto de control.

Error: El enlace solo se puede realizar con IReadOnlyList<Document> o JArray

Este error suele ocurrir si tu proyecto de Azure Functions contiene una referencia manual al paquete NuGet del SDK de Azure Cosmos DB con una versión conflictiva. Esto es común cuando la versión del paquete es diferente a la proporcionada por la extensión de Azure Cosmos DB para Azure Functions.

Solución: Elimina la referencia manual al paquete NuGet del SDK de Azure Cosmos DB y deja que la referencia al SDK se resuelva a través del paquete de extensión de Azure Cosmos DB para Azure Functions.

Cambiar el intervalo de sondeo del disparador para detectar cambios

Como se mencionó anteriormente, el disparador de Azure Functions espera un tiempo configurable (por defecto, 5 segundos) antes de verificar si hay nuevos cambios para evitar un consumo elevado de RUs. Puedes modificar este tiempo de espera a través de la configuración FeedPollDelay/feedPollDelay en la configuración del disparador (el valor se espera en milisegundos).

En resumen, los disparadores son el corazón de la reactividad en Azure Functions. Comprender su funcionamiento y cómo combinarlos con los enlaces te permitirá construir aplicaciones serverless eficientes y escalables que responden de manera inteligente a los eventos en tu entorno de Azure.

Subir