You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 11:50:07