CloudFormation自定义资源超时方案咨询:Lambda还是CustomResource属性?
Alright, let's tackle this question head-on—this is a super common gotcha with CloudFormation custom resources and Lambda, so it’s great you’re digging into the details!
Short Answer: You Need Both Configurations
You can’t rely on just one—you have to set the timeout in the CloudFormation Custom Resource AND implement proactive timeout logic in your Lambda function. Let’s break down why and how to do each part.
1. CloudFormation Custom Resource Timeout Setting
First, define the Timeout property in your CloudFormation template’s custom resource. This tells CloudFormation how long it should wait for a response from your Lambda before marking the resource as failed.
- The value is in minutes, with a maximum of 120 (2 hours).
- You should set this to be slightly longer than your Lambda’s timeout (e.g., if Lambda is set to 14 minutes, set Custom Resource timeout to 15 minutes). This gives your Lambda enough buffer to detect an impending timeout and send a proper error response to CloudFormation.
Example template snippet:
MyCustomResource: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt MyCustomResourceLambda.Arn Timeout: 15 # Minutes, matches our Lambda's 14min timeout plus buffer
2. Proactive Timeout Logic in Lambda
The Lambda’s built-in timeout will kill the function without sending a response to CloudFormation if it hits the limit. To avoid this, you need to add logic to check how much time is left during execution, and if you’re approaching the timeout, send a deliberate failure response to CloudFormation.
Here’s a step-by-step implementation using Python (the logic translates easily to other languages):
Step 1: Get Lambda’s Timeout Value
Lambda exposes its timeout (in seconds) via the environment variable AWS_LAMBDA_FUNCTION_TIMEOUT. We’ll use this to calculate our safety threshold.
Step 2: Track Execution Time
Record the start time of your function, then periodically check how much time has passed during your long-running operations.
Step 3: Send Failure Response When Approaching Timeout
If remaining time drops below a safe threshold (e.g., 30 seconds—enough time to send the response), construct an error response and post it to CloudFormation’s callback URL.
Example Lambda code:
import time import requests import os def lambda_handler(event, context): # Get Lambda timeout (in seconds) from environment variable lambda_timeout = int(os.environ['AWS_LAMBDA_FUNCTION_TIMEOUT']) # Set a safety threshold (30 seconds before timeout) timeout_threshold = lambda_timeout - 30 start_time = time.time() # Your core business logic here (e.g., calling APIs, processing data) try: while True: # Check remaining time elapsed_time = time.time() - start_time remaining_time = lambda_timeout - elapsed_time if remaining_time < timeout_threshold: # We're approaching timeout—send failure response to CloudFormation send_cloudformation_response(event, context, "FAILED", "Lambda execution approaching timeout, aborting") return # Continue your work here... # For example: process a batch of data, call an external API, etc. # If your work is a single long call, wrap it with a timeout (e.g., using requests with timeout) except Exception as e: send_cloudformation_response(event, context, "FAILED", f"Error during execution: {str(e)}") return # If everything succeeds send_cloudformation_response(event, context, "SUCCESS", "Resource processed successfully") def send_cloudformation_response(event, context, status, reason): """Send a response to CloudFormation's callback URL""" response_body = { "Status": status, "Reason": reason, "PhysicalResourceId": context.log_stream_name, "StackId": event["StackId"], "RequestId": event["RequestId"], "LogicalResourceId": event["LogicalResourceId"], "NoEcho": False } try: requests.post( event["ResponseURL"], json=response_body, headers={"Content-Type": ""}, timeout=10 ) except Exception as e: print(f"Failed to send response to CloudFormation: {str(e)}")
Why Both Are Necessary
- Only Custom Resource Timeout: If Lambda hits its own timeout, it dies without sending a response. CloudFormation will wait until the Custom Resource timeout expires (up to 2 hours) before marking the resource as failed—this causes unnecessary delays.
- Only Lambda Timeout Logic: If the Custom Resource timeout is set too low, CloudFormation might mark the resource as failed before your Lambda can finish processing or send a response.
By combining both, you ensure CloudFormation doesn’t wait unnecessarily, and your Lambda always communicates its status clearly.
内容的提问来源于stack exchange,提问作者Rudzianko怒

