AWS Lambda自定义资源传FAILED状态,CloudFormation仍收到SUCCESS
CloudFormation自定义资源始终收到SUCCESS状态的问题排查与解决
问题描述
使用cfn-response-promise的send函数返回FAILED状态时,CloudFormation始终收到SUCCESS事件,即使代码已进入异常捕获分支。
排查与解决步骤
1. 确认异常是否被正确捕获
先在catch块中添加详细错误日志,验证是否真的触发了失败分支:
catch (error) { console.error("执行出错:", error); // 打印完整错误栈信息 return await send(event, context, FAILED, { Message: `执行失败: ${(error as Error).message}` }); }
查看Lambda日志,如果未出现这条错误日志,说明异常未被捕获(需检查是否存在未处理的异步操作)。
2. 替换cfn-response-promise为手动响应
部分第三方cfn-response-promise包可能存在状态处理bug,建议直接手动构造响应发送给CloudFormation:
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager"; import { Client } from "pg"; import fetch from 'node-fetch'; const secretsManager = new SecretsManagerClient({ region: process.env.AWS_REGION }); export const handler = async (event: any, context: any) => { console.log("收到事件:", JSON.stringify(event)); let responseStatus = 'SUCCESS'; let responseData = { Message: '函数执行成功!' }; let responseReason = ''; try { // 获取PostgreSQL密钥 const secretArn = process.env.POSTGRES_SECRET_ARN; const secretResponse = await secretsManager.send(new GetSecretValueCommand({ SecretId: secretArn })); if (!secretResponse.SecretString) throw new Error("未找到密钥内容!"); const dbCredentials = JSON.parse(secretResponse.SecretString); // 连接数据库 const client = new Client({ host: process.env.POSTGRES_HOST, port: dbCredentials.port, user: dbCredentials.username, password: dbCredentials.password, database: dbCredentials.dbname, ssl: { rejectUnauthorized: false }, }); await client.connect(); console.log("已连接PostgreSQL"); // 执行SQL语句(此处添加你的逻辑) await client.end(); } catch (error) { console.error("执行出错:", error); responseStatus = 'FAILED'; responseData = { Message: '函数执行失败!' }; responseReason = (error as Error).message; } // 构造CloudFormation响应 const responseBody = JSON.stringify({ Status: responseStatus, Reason: responseReason || `${responseStatus}状态已返回`, PhysicalResourceId: context.logStreamName, StackId: event.StackId, RequestId: event.RequestId, LogicalResourceId: event.LogicalResourceId, Data: responseData }); // 发送响应 try { await fetch(event.ResponseURL, { method: 'PUT', headers: { 'Content-Type': '', 'Content-Length': responseBody.length.toString() }, body: responseBody }); console.log(`响应已发送: ${responseStatus}`); } catch (sendError) { console.error("发送响应失败:", sendError); throw sendError; } };
手动发送响应能完全控制响应内容,避免第三方包的潜在问题。
3. 检查Lambda运行环境与权限
- 确保Lambda函数能访问互联网(若PostgreSQL在公网),或配置VPC端点访问Secrets Manager和S3(CloudFormation响应URL为S3预签名URL)。
- 确认Lambda的IAM角色拥有
secretsmanager:GetSecretValue权限,可获取指定的PostgreSQL密钥。
内容的提问来源于stack exchange,提问作者SeeSharp
相关产品推荐
相关产品推荐

