hace 8 años
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.

- ¿Qué son Exactamente los Disparadores en Azure Functions?
- Disparadores vs. Enlaces: Entendiendo la Diferencia
- Beneficios Clave de Utilizar Disparadores y Enlaces
- Ejemplos Prácticos de Escenarios con Disparadores y Enlaces
- Definición de Disparadores y Enlaces en Diferentes Lenguajes
- Añadir Enlaces a una Función Existente
- Enlaces Soportados en Azure Functions
- Ejemplos de Código de Enlaces
- Enlaces Personalizados
- Preguntas Frecuentes sobre Disparadores en Azure Functions
- Mi función de Azure falla con el mensaje de error "La colección 'nombre-de-colección' no existe"
- Mis cambios tardan demasiado en ser recibidos por la función
- Algunos cambios se repiten en mi disparador
- Faltan algunos cambios en mi disparador
- Necesito reiniciar y reprocesar todos los elementos de mi contenedor desde el principio
- Error: El enlace solo se puede realizar con IReadOnlyList<Document> o JArray
- Cambiar el intervalo de sondeo del disparador para detectar cambios
¿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:
| Escenario | Disparador | Enlace de Entrada | Enlace de Salida |
|---|---|---|---|
| Llega un nuevo mensaje a una cola y se ejecuta una función para escribir en otra cola. | Cola* | Ninguno | Cola* |
| Un trabajo programado lee contenido de Blob Storage y crea un nuevo documento en Azure Cosmos DB. | Temporizador (Timer) | Blob Storage | Azure 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 Grid | Blob Storage y Azure Cosmos DB | SendGrid |
* 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.

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.
| Servicio | Disparador | Entrada | Salida | Ejemplos y Muestras |
|---|---|---|---|---|
| Blob Storage | Enlace | |||
| Azure Cosmos DB | Enlace | |||
| Azure Data Explorer | Enlace | |||
| Azure SQL | Enlace | |||
| Event Grid | Enlace | |||
| Event Hubs | ||||
| IoT Hub | ||||
| HTTP | Enlace | |||
| Queue storage | Enlace | |||
| RabbitMQ | ||||
| SendGrid | ||||
| Service Bus | Enlace | |||
| SignalR | ||||
| Table storage | ||||
| Timer | Enlace | |||
| Twilio | Enlace |
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
Connectiondel 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
databaseNameycontainerNameexistan 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 esleases. Asegúrate de que exista una colección con ese nombre para las concesiones. - Opcionalmente, puedes establecer el atributo
CreateLeaseContainerIfNotExistsen tu disparador atruepara 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
PreferredLocationsen 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
_lsnpara 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/catchen 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/leaseCollectionPrefixdiferente 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:
- Detén tu función de Azure si está en ejecución.
- Elimina los documentos de la colección de concesiones (o elimina y vuelve a crear la colección para que esté vacía).
- Establece el atributo
StartFromBeginningdel disparadorCosmosDBTriggerentrue. - 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.
