This rule raises an issue when network calls in AWS Lambda functions are made without explicit timeout parameters.

Why is this an issue?

AWS Lambda functions are ephemeral, event-driven compute services that frequently interact with external systems including other AWS services via boto3, external APIs through HTTP requests, databases, and message brokers. When these network calls are made without explicit timeout parameters, the Lambda function becomes vulnerable to indefinite hanging if the remote service becomes unresponsive due to network issues, service overload, or connectivity problems. Unlike traditional server environments where hanging requests might affect only a single user session, Lambda functions that hang continue to consume billable compute time until the function’s maximum execution timeout is reached, which can be up to 15 minutes. This creates a cascading effect where network reliability issues directly translate to increased operational costs and unpredictable system behavior.

What is the potential impact?

Hanging executions lead to increased AWS costs due to wasted compute time while waiting for unresponsive services. The lack of explicit timeouts causes unpredictable failure behavior, making it difficult to distinguish between functional errors and network stalls, which complicates debugging and monitoring. When the Lambda function’s maximum timeout is reached, the execution is abruptly terminated, preventing graceful error handling, proper logging, and cleanup operations. In connection pooling scenarios, hanging requests can exhaust available connections, and the unpredictable delays can cause cascading failures in upstream services that depend on the Lambda function’s response.

How to fix it in Requests

For HTTP requests using the requests library, always specify the timeout parameter. Use a tuple (connect_timeout, read_timeout) for granular control over connection establishment and data reading timeouts. Wrap the call in try-except blocks to handle timeout exceptions gracefully. Consider externalizing timeout values through environment variables for easier configuration management.

Code examples

Noncompliant code example

import requests

def lambda_handler(event, context):
    response = requests.get('https://api.example.com/data')  # Noncompliant
    return response.json()

Compliant solution

import requests
import os

def lambda_handler(event, context):
    try:
        timeout = (float(os.environ.get('CONNECT_TIMEOUT', 3)),
                  float(os.environ.get('READ_TIMEOUT', 10)))
        response = requests.get('https://api.example.com/data', timeout=timeout)
        return response.json()
    except requests.exceptions.Timeout:
        return {'error': 'Request timed out'}

How to fix it in Boto3

For AWS service calls using boto3, configure timeouts using botocore.config.Config when creating clients. Set both connect_timeout and read_timeout parameters to prevent hanging on connection establishment and data reading respectively. Handle botocore timeout exceptions appropriately in your error handling logic.

Code examples

Noncompliant code example

import boto3

def lambda_handler(event, context):
    s3 = boto3.client('s3')  # Noncompliant
    response = s3.get_object(Bucket='my-bucket', Key='my-key')
    return response['Body'].read()

Compliant solution

import boto3
from botocore.config import Config
from botocore.exceptions import ReadTimeoutError, ConnectTimeoutError

def lambda_handler(event, context):
    try:
        config = Config(connect_timeout=5, read_timeout=10)
        s3 = boto3.client('s3', config=config)
        response = s3.get_object(Bucket='my-bucket', Key='my-key')
        return response['Body'].read()
    except (ReadTimeoutError, ConnectTimeoutError):
        return {'error': 'AWS service call timed out'}

Resources

Documentation