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:

[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:

Pasos siguientes