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

使用aws-cdk@2.59.0部署CloudFormation栈时自定义资源偶发状态权限错误求助

错误原因与解决方案:Custom Resource 报 Resource is not in the state functionActiveV2

错误原因

这个偶发错误的核心是自定义资源触发执行时,目标Lambda函数(或其依赖的Lambda)尚未完成状态切换到functionActiveV2:

  • CloudFormation默认会并行创建/更新资源,即使显式设置了资源依赖,Lambda内部的状态同步(比如发布新版本、更新配置后的状态刷新)可能存在不稳定的延迟。
  • 当Lambda处于Pending或Updating等过渡状态时,对其发起调用请求就会返回AccessDeniedException并附带该状态提示,这种情况只会在Lambda状态切换较慢时出现,因此错误具有偶发性。

解决方法

1. 依赖Lambda的稳定版本/别名而非原始函数

CloudFormation会等待Lambda的Version或Alias资源完全就绪后,再创建依赖它的自定义资源,能从根源上避免状态未就绪的问题。在CDK中可以这样实现:

import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as custom_resources from 'aws-cdk-lib/custom-resources';
import { Construct } from 'constructs';

export class MyStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // 创建Lambda函数,开启自动发布版本
    const myLambda = new lambda.Function(this, 'TargetLambda', {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: 'index.handler',
      code: lambda.Code.fromAsset('lambda'),
      publish: true,
    });

    // 使用函数的当前稳定版本作为自定义资源的事件处理器
    const lambdaStableVersion = myLambda.currentVersion;
    const customProvider = new custom_resources.Provider(this, 'CustomResourceProvider', {
      onEventHandler: lambdaStableVersion,
    });

    // 创建自定义资源,依赖稳定版本的Lambda
    new cdk.CustomResource(this, 'MyCustomResource', {
      serviceToken: customProvider.serviceToken,
    });
  }
}

2. 在自定义资源代码中添加重试逻辑

针对偶发的状态延迟,在自定义资源的Lambda处理函数中捕获特定错误并进行指数退避重试,等待Lambda状态就绪:

const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();

const MAX_RETRIES = 3;
const BASE_DELAY = 1000; // 初始延迟1秒

async function handler(event) {
  let retryCount = 0;
  
  while (retryCount < MAX_RETRIES) {
    try {
      // 替换为你的业务逻辑,比如调用目标Lambda
      const response = await lambda.invoke({
        FunctionName: process.env.TARGET_LAMBDA_ARN,
        Payload: JSON.stringify(event)
      }).promise();

      return {
        Status: 'SUCCESS',
        Data: {
          result: JSON.parse(response.Payload)
        }
      };
    } catch (error) {
      // 判断是否为目标状态错误
      if (error.code === 'AccessDeniedException' && error.message.includes('functionActiveV2')) {
        retryCount++;
        const delay = BASE_DELAY * Math.pow(2, retryCount - 1); // 指数退避:1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      // 其他错误直接抛出,标记自定义资源失败
      return {
        Status: 'FAILED',
        Reason: error.message,
        PhysicalResourceId: event.PhysicalResourceId
      };
    }
  }

  // 重试耗尽仍失败
  return {
    Status: 'FAILED',
    Reason: `重试${MAX_RETRIES}次后,目标Lambda仍未就绪`,
    PhysicalResourceId: event.PhysicalResourceId
  };
}

exports.handler = handler;

3. 优化Lambda部署配置

  • 始终为用于自定义资源的Lambda设置publish: true,确保函数创建时就生成稳定的版本,避免调用未发布的过渡态函数。
  • 避免在自定义资源中直接引用Lambda的原始ARN(无版本/别名后缀),优先使用带版本或别名的ARN,确保调用的是稳定状态的函数实例。

4. 验证IAM权限

虽然错误由状态问题引发,但仍需确认自定义资源的执行角色拥有lambda:InvokeFunction权限,且权限范围覆盖目标Lambda的完整ARN(包括版本/别名的ARN),避免因权限不足误报状态错误。

内容的提问来源于stack exchange,提问作者Pavlo Zhoholiev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 15:43:14