Reintentos y control de errores de Azure Functions
El control de los errores en Azure Functions es importante para ayudarle a evitar la pérdida de datos, evitar eventos perdidos y para supervisar el estado de la aplicación. También es una forma importante de ayudarle a comprender los comportamientos de reintento de los desencadenadores basados en eventos.
En este artículo se describen las estrategias generales para el control de errores y las estrategias de reintento disponibles.
Importante
La compatibilidad con la directiva de reintento de versión preliminar para determinados desencadenadores se quitó en diciembre de 2022. Las directivas de reintento para los desencadenadores admitidos ahora están disponibles con carácter general (GA). Para obtener una lista de las extensiones que admiten actualmente directivas de reintento, consulte la sección Reintentos.
Control de errores
Los errores que se producen en una función de Azure pueden proceder de:
- Uso de desencadenadores y enlaces de Azure Functions integrados
- Llamadas a las API de los servicios de Azure subyacentes.
- Llamadas a puntos de conexión REST.
- Llamadas a bibliotecas de cliente, paquetes o API de terceros.
Para evitar la pérdida de datos o mensajes perdidos es importante llevar a cabo un buen control de errores. Esta sección describe algunas prácticas recomendadas para el manejo de errores y proporciona enlaces a más información.
Recomendación | Detalles |
---|---|
Habilitar Application Insights | Azure Functions se integra con Application Ideas para recopilar datos de error, datos de rendimiento y registros en tiempo de ejecución. Debería usar Application Insights para detectar y comprender mejor los errores que ocurran en las ejecuciones de funciones. Para más información, consulte Supervisión de Azure Functions. |
Uso del control de errores estructurado | La captura y el registro de los errores son fundamentales para supervisar el estado de la aplicación. El nivel superior de cualquier código de función debe incluir un bloque try/catch. En el bloque catch, puede capturar y registrar errores. Para obtener información sobre los errores que pueden generar los enlaces, consulte Códigos de error de enlace. En función de la estrategia de reintento específica, también puede generar una nueva excepción para volver a ejecutar la función. |
Planificación la estrategia de reintento | Varias extensiones de enlaces de Functions proporcionan compatibilidad integrada con reintentos y otras permiten definir directivas de reintento, que se implementan en el entorno de ejecución de Functions. En el caso de los desencadenadores que no proporcionan comportamientos de reintento, debe considerar la posibilidad de implementar su propio esquema de reintento. Para obtener más información, vea Reintentos. |
Diseño para idempotencia | La aparición de errores al procesar datos podría suponer un problema para las funciones, especialmente al procesar mensajes. Es importante tener en cuenta lo que suceda cuando se produzca el error y cómo evitar el procesamiento duplicado. Para obtener más información, vea Diseño de funciones de Azure para entradas idénticas. |
Reintentos
Hay dos tipos de reintentos disponibles para sus funciones:
- Comportamientos de reintento integrados de extensiones de desencadenador individuales
- Directivas de reintento proporcionadas por el runtime de Functions
En la tabla siguiente se indica qué desencadenadores admiten reintentos y dónde se configura el comportamiento de reintento. También vincula a más información sobre los errores que proceden de los servicios subyacentes.
Desencadenadores o enlaces | Origen de reintento | Configuración |
---|---|---|
Azure Cosmos DB | Directivas de reintentos | Nivel de función |
Blob Storage | Extensión de enlace | host.json |
Event Grid | Extensión de enlace | Suscripción a eventos |
Event Hubs | Directivas de reintentos | Nivel de función |
Kafka | Directivas de reintentos | Nivel de función |
Queue Storage | Extensión de enlace | host.json |
RabbitMQ | Extensión de enlace | Cola de mensajes fallidos |
Service Bus | Extensión de enlace | host.json* |
Temporizador | Directivas de reintentos | Nivel de función |
*Requiere la versión 5.x de la extensión de Azure Service Bus. En versiones anteriores de la extensión, la cola de mensajes fallidos de Service Bus implementa los comportamientos de reintento.
Directivas de reintentos
Azure Functions le permite definir directivas de reintento para tipos de desencadenadores específicos, que el tiempo de ejecución aplica. Actualmente, estos tipos de desencadenadores admiten directivas de reintento:
La compatibilidad con reintentos es la misma para los modelos de programación de Python v1 y v2.
Las directivas de reintento no se admiten en la versión 1.x del entorno de ejecución de Functions.
La directiva de reintentos indica al tiempo de ejecución que vuelva a ejecutar una ejecución errónea hasta que se complete correctamente o se alcance el número máximo de reintentos.
Una directiva de reintento se evalúa cuando una función ejecutada por un tipo de desencadenador admitido genera una excepción no detectada. Como procedimiento recomendado, debería detectar todas las excepciones del código y volver a generar los errores que quiere que vuelva dar lugar a un reintento.
Importante
Los puntos de control de Event Hubs no se escriben hasta que la política de reintentos de la ejecución ha finalizado. Debido a este comportamiento, el progreso en la partición específica se pausa hasta que el lote actual termine de procesarse.
La versión 5.x de la extensión de concentradores de eventos soporta capacidades adicionales de reintento para las interacciones entre el host de funciones y el concentrador de eventos. Para obtener más información, consulte clientRetryOptions
la referencia de host.json de Event Hubs.
Estrategia de reintento
Es posible configurar dos estrategias de reintento compatibles con la directiva:
Puede transcurrir un período de tiempo especificado entre cada reintento.
Cuando se ejecuta en un plan de consumo, solo se le factura el tiempo en que se ejecuta el código de función. No se le factura el tiempo de espera entre las ejecuciones en ninguna de estas estrategias de reintento.
Número máximo de reintentos
Puede configurar el número máximo de veces que se reintenta una ejecución de función antes de que se produzca un error eventual. El número de reintentos actual se almacena en la memoria de la instancia.
Es posible que una instancia de un error entre reintentos. Cuando se produce un error en una instancia durante una directiva de reintentos, se pierde el número de reintentos. Cuando hay errores de instancia, el desencadenador de Event Hubs puede reanudar el procesamiento y reintentar el lote en una nueva instancia, con el número de reintentos restablecido en cero. El desencadenador de temporizador no se reanuda en una nueva instancia.
Este comportamiento significa que el número máximo de reintentos es un mejor esfuerzo. En algunos casos excepcionales, se podría reintentar una ejecución más que el número máximo solicitado de veces. En el caso de los desencadenadores de Temporizador, los reintentos pueden ser menores que el número máximo solicitado.
Ejemplos de reintentos
Se proporcionan ejemplos para estrategias de retraso fijo y retroceso exponencial. Para ver ejemplos de una estrategia específica, primero debe seleccionar esa estrategia en la pestaña anterior.
Los reintentos de nivel de función se admiten con los siguientes paquetes NuGet:
- Microsoft.Azure.Functions.Worker.Sdk>= 1.9.0
- Microsoft.Azure.Functions.Worker.Extensions.EventHubs>= 5.2.0
- Microsoft.Azure.Functions.Worker.Extensions.Kafka>= 3.8.0
- Microsoft.Azure.Functions.Worker.Extensions.Timer>= 4.2.0
[Function(nameof(TimerFunction))]
[FixedDelayRetry(5, "00:00:10")]
public static void Run([TimerTrigger("0 */5 * * * *")] TimerInfo timerInfo,
FunctionContext context)
{
var logger = context.GetLogger(nameof(TimerFunction));
logger.LogInformation($"Function Ran. Next timer schedule = {timerInfo.ScheduleStatus?.Next}");
}
Propiedad | Descripción |
---|---|
MaxRetryCount | Necesario. Número máximo de reintentos permitidos por ejecución de función. -1 significa que se reintentará indefinidamente. |
DelayInterval | Retraso utilizado entre reintentos. Especifíquelo como una cadena con el formato HH:mm:ss . |
Este es un ejemplo de una directiva de reintento definida en el archivo function.json:
{
"disabled": false,
"bindings": [
{
....
}
],
"retry": {
"strategy": "fixedDelay",
"maxRetryCount": 4,
"delayInterval": "00:00:10"
}
}
Puede establecer estas propiedades en las definiciones de directiva de reintento:
Propiedad | Descripción |
---|---|
strategy | Necesario. Estrategia de reintentos que se usará. Los valores válidos son fixedDelay y exponentialBackoff . |
maxRetryCount | Necesario. Número máximo de reintentos permitidos por ejecución de función. -1 significa que se reintentará indefinidamente. |
delayInterval | Retraso que se usa entre reintentos al utilizar la estrategia fixedDelay . Especifíquelo como una cadena con el formato HH:mm:ss . |
minimumInterval | Retraso mínimo entre reintentos al usar la estrategia exponentialBackoff . Especifíquelo como una cadena con el formato HH:mm:ss . |
maximumInterval | Retraso entre reintentos máximo al usar la estrategia exponentialBackoff . Especifíquelo como una cadena con el formato HH:mm:ss . |
La forma de definir la directiva de reintento para el desencadenador depende de la versión de Node.js.
Este es un ejemplo de una función de desencadenador de temporizador que usa una estrategia de reintento de retraso fijo:
const { app } = require('@azure/functions');
app.timer('timerTriggerWithRetry', {
schedule: '0 */5 * * * *',
retry: {
strategy: 'fixedDelay',
delayInterval: {
seconds: 10,
},
maxRetryCount: 4,
},
handler: (myTimer, context) => {
if (context.retryContext?.retryCount < 2) {
throw new Error('Retry!');
} else {
context.log('Timer function processed request.');
}
},
});
La forma de definir la directiva de reintento para el desencadenador depende de la versión de Node.js.
Este es un ejemplo de una función de desencadenador de temporizador que usa una estrategia de reintento de retraso fijo:
import { app, InvocationContext, Timer } from '@azure/functions';
export async function timerTriggerWithRetry(myTimer: Timer, context: InvocationContext): Promise<void> {
if (context.retryContext?.retryCount < 2) {
throw new Error('Retry!');
} else {
context.log('Timer function processed request.');
}
}
app.timer('timerTriggerWithRetry', {
schedule: '0 */5 * * * *',
retry: {
strategy: 'fixedDelay',
delayInterval: {
seconds: 10,
},
maxRetryCount: 4,
},
handler: timerTriggerWithRetry,
});
Puede establecer estas propiedades en las definiciones de directiva de reintento:
Propiedad | Descripción |
---|---|
strategy | Necesario. Estrategia de reintentos que se usará. Los valores válidos son fixedDelay y exponentialBackoff . |
maxRetryCount | Necesario. Número máximo de reintentos permitidos por ejecución de función. -1 significa que se reintentará indefinidamente. |
delayInterval | Retraso que se usa entre reintentos al utilizar la estrategia fixedDelay . Especifíquelo como una cadena con el formato HH:mm:ss . |
minimumInterval | Retraso mínimo entre reintentos al usar la estrategia exponentialBackoff . Especifíquelo como una cadena con el formato HH:mm:ss . |
maximumInterval | Retraso entre reintentos máximo al usar la estrategia exponentialBackoff . Especifíquelo como una cadena con el formato HH:mm:ss . |
Este es un ejemplo de una función de desencadenador de temporizador que usa una estrategia de reintento de retraso fijo:
import logging
from azure.functions import AuthLevel, Context, FunctionApp, TimerRequest
app = FunctionApp(http_auth_level=AuthLevel.ANONYMOUS)
@app.timer_trigger(schedule="*/1 * * * * *", arg_name="mytimer",
run_on_startup=False,
use_monitor=False)
@app.retry(strategy="fixed_delay", max_retry_count="3",
delay_interval="00:00:01")
def mytimer(mytimer: TimerRequest, context: Context) -> None:
logging.info(f'Current retry count: {context.retry_context.retry_count}')
if context.retry_context.retry_count == \
context.retry_context.max_retry_count:
logging.info(
f"Max retries of {context.retry_context.max_retry_count} for "
f"function {context.function_name} has been reached")
else:
raise Exception("This is a retryable exception")
Puede establecer estas propiedades en las definiciones de directiva de reintento:
Propiedad | Descripción |
---|---|
strategy | Necesario. Estrategia de reintentos que se usará. Los valores válidos son fixed_delay y exponential_backoff . |
max_retry_count | Necesario. Número máximo de reintentos permitidos por ejecución de función. -1 significa que se reintentará indefinidamente. |
delay_interval | Retraso que se usa entre reintentos al utilizar la estrategia fixed_delay . Especifíquelo como una cadena con el formato HH:mm:ss . |
minimum_interval | Retraso mínimo entre reintentos al usar la estrategia exponential_backoff . Especifíquelo como una cadena con el formato HH:mm:ss . |
maximum_interval | Retraso entre reintentos máximo al usar la estrategia exponential_backoff . Especifíquelo como una cadena con el formato HH:mm:ss . |
@FunctionName("TimerTriggerJava1")
@FixedDelayRetry(maxRetryCount = 4, delayInterval = "00:00:10")
public void run(
@TimerTrigger(name = "timerInfo", schedule = "0 */5 * * * *") String timerInfo,
final ExecutionContext context
) {
context.getLogger().info("Java Timer trigger function executed at: " + LocalDateTime.now());
}
Códigos de error de enlace
Cuando se realicen integraciones con los servicios de Azure, podrían originarse errores desde las API de los servicios subyacentes. La información relacionada con errores específicos de enlace está disponible en las secciones "Excepciones y códigos de retorno" de los siguientes artículos:
- Azure Cosmos DB
- Blob Storage
- Event Grid
- Event Hubs
- IoT Hub
- Centros de notificaciones
- Queue Storage
- Service Bus
- Table Storage