¿Cómo soluciono los problemas de reintento y tiempo de espera cuando uso un AWS SDK para invocar una función de Lambda?

8 minutos de lectura
0

Cuando invoco mi función de AWS Lambda con un AWS SDK, se agota el tiempo de espera de la función, la solicitud de la API da error o se duplica una acción de la API.

Descripción corta

Pueden producirse problemas de reintento y tiempo de espera al invocar una función de Lambda con un AWS SDK debido a las siguientes condiciones:

  • No se puede acceder a una API remota o se tarda demasiado en responder a una llamada a la API.
  • La llamada a la API no recibe respuesta dentro del tiempo de espera del socket.
  • La llamada a la API no recibe respuesta dentro del periodo de tiempo de espera de la función de Lambda.

Nota: Las llamadas a la API pueden tardar más de lo esperado cuando se producen problemas de conexión a la red. Los problemas de red también pueden provocar reintentos y solicitudes de API duplicadas. Para prepararte para estos casos, asegúrate de que la función de Lambda sea idempotente.

Si utilizas un AWS SDK para realizar una llamada a la API y la llamada falla, el AWS SDK vuelve a intentar la llamada automáticamente. La cantidad de veces que el AWS SDK reintenta las llamadas y durante cuánto tiempo depende de la configuración, que varía de un AWS SDK a otro.

Configuración de reintento predeterminada de AWS SDK

Nota: Algunos valores pueden ser diferentes para otros servicios de AWS.

AWS SDKNúmero máximo de reintentosTiempo de espera de conexiónTiempo de espera del socket
Python (Boto 3)En función del servicio60 segundos60 segundos
JavaScript/Node.jsEn función del servicioN/D120 segundos
Java310 segundos50 segundos
.NET4100 segundos300 segundos
Go3N/DN/D

Para solucionar los problemas de reintento y tiempo de espera, primero revisA los registros de la llamada a la API para localizar el problema. A continuación, cambia la configuración del número de reintentos y el tiempo de espera de AWS SDK según sea necesario en cada caso. Para dejar suficiente tiempo para responder a la llamada a la API, añade un tiempo a la configuración del tiempo de espera de la función de Lambda.

Resolución

Registro de las llamadas a la API realizadas por AWS SDK

Utiliza los Registros de Amazon CloudWatch para obtener detalles sobre las conexiones fallidas y el número de reintentos para cada una de ellas. Para obtener más información, consulta Uso de registros de Registros de CloudWatch con Lambda. También puedes consultar las siguientes instrucciones para el AWS SDK que estés utilizando:

Ejemplo de registro de errores en el que la llamada a la API no pudo establecer una conexión (tiempo de espera de conexión)

START RequestId: b81e56a9-90e0-11e8-bfa8-b9f44c99e76d Version: $LATEST2018-07-26T14:32:27.393Z    b81e56a9-90e0-11e8-bfa8-b9f44c99e76d    [AWS ec2 undefined 40.29s 3 retries] describeInstances({})
2018-07-26T14:32:27.393Z    b81e56a9-90e0-11e8-bfa8-b9f44c99e76d    { TimeoutError: Socket timed out without establishing a connection

...

Ejemplo de registro de errores en el que la conexión a la llamada a la API se realizó correctamente, pero se agotó el tiempo de espera después de que la respuesta a la API tardara demasiado (tiempo de espera del socket)

START RequestId: 3c0523f4-9650-11e8-bd98-0df3c5cf9bd8 Version: $LATEST2018-08-02T12:33:18.958Z    3c0523f4-9650-11e8-bd98-0df3c5cf9bd8    [AWS ec2 undefined 30.596s 3 retries] describeInstances({})2018-08-02T12:33:18.978Z    3c0523f4-9650-11e8-bd98-0df3c5cf9bd8    { TimeoutError: Connection timed out after 30s

Nota: Estos registros no se generan si la solicitud de la API no recibe una respuesta dentro del tiempo de espera de la función de Lambda. Si la solicitud de la API finaliza debido a que se ha agotado el tiempo de espera de una función, pruebe una de las siguientes opciones:

Cambio de la configuración de AWS SDK

La configuración del número de reintentos y el tiempo de espera de AWS SDK deberían permitir tiempo suficiente para que la llamada a la API reciba una respuesta. Para determinar los valores correctos para cada ajuste, pruebe diferentes configuraciones y obtenga la siguiente información:

  • Tiempo promedio para establecer una conexión satisfactoria
  • Tiempo promedio que tarda una solicitud de API completa (hasta que se devuelva correctamente)

Para obtener más información sobre cómo cambiar la configuración del número de reintentos y el tiempo de espera, consulta la siguiente documentación sobre configuración del cliente AWS SDK:

A continuación se muestran algunos comandos de ejemplo que cambian la configuración del número de reintentos y el tiempo de espera para cada tiempo de ejecución.

Nota: Asegúrate de reemplazar los valores de ejemplo de cada configuración por los valores de tu caso práctico.

Ejemplo de comando de Python (Boto 3) para cambiar la configuración del número de reintentos y el tiempo de espera

# max_attempts: retry count / read_timeout: socket timeout / connect_timeout: new connection timeout
from botocore.session import Session
from botocore.config import Config

s = Session()
c = s.create_client('s3', config=Config(connect_timeout=5, read_timeout=60, retries={'max_attempts': 2}))

Ejemplo de comando de JavaScript/Node.js para cambiar la configuración del número de reintentos y el tiempo de espera

// maxRetries: retry count / timeout: socket timeout / connectTimeout: new connection timeout
var AWS = require('aws-sdk');

AWS.config.update({

    maxRetries: 2,

    httpOptions: {

        timeout: 30000,

        connectTimeout: 5000

    }

});

Ejemplo de comando de JavaScript V3 para cambiar la configuración del número de reintentos y el tiempo de espera

const { S3Client, ListBucketsCommand } = require("@aws-sdk/client-s3");
const { NodeHttpHandler } = require("@aws-sdk/node-http-handler");
const client = new S3Client({
    requestHandler: new NodeHttpHandler({
        connectionTimeout: 30000,
        socketTimeout: 50000
    }),
    maxAttempts: 2
});

Ejemplo de comando de Java para cambiar la configuración del número de reintentos y el tiempo de espera

// setMaxErrorRetry(): retry count / setSocketTimeout(): socket timeout / setConnectionTimeout(): new connection timeout
ClientConfiguration clientConfig = new ClientConfiguration();

clientConfig.setSocketTimeout(60000);
clientConfig.setConnectionTimeout(5000);
clientConfig.setMaxErrorRetry(2);

AmazonDynamoDBClient ddb = new AmazonDynamoDBClient(credentialsProvider,clientConfig);

Ejemplo de comando de .NET para cambiar la configuración del número de reintentos y el tiempo de espera

// MaxErrorRetry: retry count / ReadWriteTimeout: socket timeout / Timeout: new connection timeout
var client = new AmazonS3Client(

    new AmazonS3Config {
        Timeout = TimeSpan.FromSeconds(5),
        ReadWriteTimeout = TimeSpan.FromSeconds(60),
        MaxErrorRetry = 2
});

Ejemplo de comando de Go para cambiar la configuración del número de reintentos

// Create Session with MaxRetry configuration to be shared by multiple service clients.sess := session.Must(session.NewSession(&aws.Config{
    MaxRetries: aws.Int(3),
}))

// Create S3 service client with a specific Region.
svc := s3.New(sess, &aws.Config{
    Region: aws.String("us-west-2"),
})

Ejemplo de comando de Go para cambiar la configuración del tiempo de espera de la solicitud

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)defer cancel()
// SQS ReceiveMessage
params := &sqs.ReceiveMessageInput{ ... }
req, resp := s.ReceiveMessageRequest(params)
req.HTTPRequest = req.HTTPRequest.WithContext(ctx)
err := req.Send()

(Opcional) Cambio de la configuración de tiempo de espera de la función de Lambda

Un tiempo de espera bajo de la función de Lambda puede provocar que las conexiones en buen estado se interrumpan antes de tiempo. Aumenta el ajuste del tiempo de espera de la función con el fin de que tu llamada a la API tenga tiempo suficiente para obtener una respuesta.

Utiliza la siguiente fórmula para calcular el tiempo de base necesario para el tiempo de espera de la función:

First attempt (connection timeout + socket timeout) + Number of retries x (connection timeout + socket timeout) + 20 seconds additional code runtime margin = Required Lambda function timeout

Ejemplo de cálculo del tiempo de espera de la función de Lambda

Nota: El siguiente cálculo es para un AWS SDK configurado para tres reintentos, un tiempo de espera de conexión de diez segundos y un tiempo de espera del socket de treinta segundos.

First attempt (10 seconds + 30 seconds) + Number of retries [3 * (10 seconds + 30 seconds)] + 20 seconds additional code runtime margin = 180 seconds

Información relacionada

Invoke

Comprender el comportamiento de reintento en Lambda

Cuotas de Lambda

OFICIAL DE AWS
OFICIAL DE AWSActualizada hace 6 meses