Comment puis-je empêcher l'expiration du délai d'expiration de ma fonction Lambda connectée à un Amazon VPC ?

Lecture de 4 minute(s)
0

Je souhaite empêcher l'expiration du délai de connexion de ma fonction AWS Lambda à un Amazon Virtual Private Cloud (Amazon VPC).

Brève description

Le fait d'invoquer des appels d'API de fonction Lambda derrière un équilibreur de charge ou une passerelle NAT sans réponse peut être dû à un problème de délai d'inactivité de connexion. La valeur du délai d'inactivité de l'équilibreur de charge est de 350 secondes pour les flux TCP.

Si le délai de réponse aux appels d'API est intermittent ou inférieur à 350 secondes, cela peut être dû à des problèmes de nouvelle tentative et de délai d'expiration. Pour plus d'informations, consultez Comment résoudre les problèmes liés aux nouvelles tentatives et au délai d'expiration lors de l'appel d'une fonction Lambda à l'aide d'un kit SDK AWS ?

Résolution

Pour éviter que la connexion ne soit interrompue, vous pouvez activer TCP keepalive avec une valeur inférieure à 350 secondes pour réinitialiser le délai d'inactivité. TCP keepalive empêche la connexion d'être inactive en envoyant des paquets aux connexions frontales et dorsales toutes les 20 secondes.

Vous pouvez appeler setKeepAlive sur l'objet socket de la manière suivante :

Nœud.js 14 et Nœud.js 16

const http = require('http');

function invokeApi() {

  return new Promise(resolve => {

    var callback = function(response) {
      var str = '';

      response.on('data', function (chunk) {
        str += chunk;
      });

      response.on('end', function () {
        response = '**** ALB response: ' + str;
        resolve(response)
      });
    }

    const url = 'http://<alb-dns>';
    const myTimeout = 1000*60*15; // 15 minutes
    let req = http.get(url, callback);

    req.on('error', (e) => {
      console.error(`Got error: ${e.message}`);
    });

    req.on('socket', function (socket) {
      socket.setKeepAlive(true, 1000); //set SO_KEEPALIVE

      socket.setTimeout(myTimeout);  

      socket.on('timeout', function() {
        console.log('request is about to timeout');
        req.abort();
      });
    });
    req.end();
  })
}

exports.handler = async (event) => {
    let output = await invokeApi();
    const response = {
        statusCode: 200,
        body: output,
    };
    return response;
};

Nœud.js 18

import * as http from "http"

function invokeApi() {

  return new Promise(resolve => {

    var callback = function(response) {
      var str = '';

      response.on('data', function (chunk) {
        str += chunk;
      });

      response.on('end', function () {
        response = '**** ALB response: ' + str;
        resolve(response);
      });
    }

    const url = 'http://<alb-dns>';
    const myTimeout = 1000*60*15; // 15 minutes
    let req = http.get(url, callback);

    req.on('error', (e) => {
      console.error(`Got error: ${e.message}`);
    });

    req.on('socket', function (socket) {
      socket.setKeepAlive(true, 1000); //set SO_KEEPALIVE

      socket.setTimeout(myTimeout);  

      socket.on('timeout', function() {
        console.log('request is about to timeout');
        req.abort();
      });
    });
    req.end();
  })
}

export const handler = async(event) => {
    let output = await invokeApi();
    const response = {
        statusCode: 200,
        body: output,
    };
    return response;
};

Python 3.x

import json
import socket
import requests
from urllib3.connection import HTTPConnection

HTTPConnection.default_socket_options = HTTPConnection.default_socket_options + [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]
def lambda_handler(event, context):
    try:
        r = requests.get("http://<alb-dns>",timeout=(5,900))

        output = r.text
    except requests.RequestException as e:
        print(e)
        raise e
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": output,
        }),
    }

À l'aide du kit SDK AWS pour Java2, vous pouvez transmettre un client HTTP préconfiguré similaire au suivant :

LambdaClient awsLambda = LambdaClient.builder()
    .region(region
    .httpClient(ApacheHttpClient.builder()
                   .tcpKeepAlive(true)
                   .connectionTimeout(Duration.ofSeconds(5))
                   .connectionMaxIdleTime(Duration.ofMinutes(15))
                   .socketTimeout(Duration.ofMinutes(15)).build())
    .build();

L'utilisation du kit SDK AWS pour Python (Boto3) vous permet d'utiliser un fichier de configuration. Créez un fichier .config avec le contenu suivant :

[default]
tcp_keepalive=true

Créez ensuite une variable d'environnement Lambda AWS_CONFIG_FILE avec la valeur du fichier .config dans le répertoire /var/task/config.

Pour plus d'informations, consultez la section Délai d'inactivité de la connexion.


Informations connexes

Annonce d'une mise en réseau VPC améliorée pour les fonctions AWS Lambda

Comment puis-je résoudre les problèmes de connectivité lors de l'utilisation de la passerelle NAT sur mon VPC privé ?

AWS OFFICIEL
AWS OFFICIELA mis à jour il y a un an