为什么我的 CloudWatch 规则被触发但没有调用我的 Lambda 函数?

Why is my CloudWatch rule triggered but not invoking my Lambda function?

我已经使用 CDK 创建了一个 Lambda 函数。

在我的 Java 应用程序中,我以编程方式创建一个 CloudWatch 事件规则,其目标通过其 ARN 指向函数。

CloudWatch 规则被触发,但未能调用 Lambda。当我从 AWS 控制台手动添加 CloudWatch 规则作为 Lambda 的触发器时,该函数会被调用。

CDK 代码

private createPregameEventsLambda(props: InfraStackProps) {
        const lambdaEnvVars = {
            'Domain': props.stage,
            'Region': props.region,
            'ResourceNamePrefix': props.resourceNamePrefix
        };

        const pregameEventsLambda = new Lambda(this, "PregameEvents-Lambda", {
            ...props,
            name: LambdaConfig.PREGAME_EVENTS_LAMBDA.name,
            handler: LambdaConfig.PREGAME_EVENTS_LAMBDA.handler,
            environment: {
                variables: lambdaEnvVars
            },
            role: this.lambdaExecutionRole
        }).getFunction()
}

Java申请:

public void createCloudWatchRule(final LiveEventIdRelationInfo info) {
        final String smpId = info.getSmpId();
        final Date date = new Date(startTime);
        final Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        calendar.setTimeZone(TimeZone.getTimeZone("GMT+0"));
        final String cronExpression =  getCronExpression(calendar);

        final PutRuleRequest putRuleRequest = new PutRuleRequest()
                .withScheduleExpression(cronExpression)
                .withName(ruleName);
        cloudWatchEventClient.putRule(putRuleRequest);

        final Target target = new Target()
                .withId(LAMBDA_TARGET_ID)
                .withArn(functionArn)
                .withInput(jsonString);
        final PutTargetsRequest putTargetsRequest = new PutTargetsRequest()
                .withRule(ruleName)
                .withTargets(target);
        cloudWatchEventClient.putTargets(putTargetsRequest);
    }

控制台显示创建的规则具有正确的 Lambda ARN,但它仍然没有被调用。

我需要向 CDK 代码添加 InvokeFunction 权限吗?

我缺少权限吗?

Is there an InvokeFunction permission I need to add to the CDK code?

不,这与您的 CDK 代码无关,因为您正在 CDK 代码之外创建新的 EventBridge (CloudWatch) 规则。您没有使用 CDK 创建规则,因此这里不适合查看。

您的 Lambda 函数缺少 resource-based IAM 策略,该策略允许 EventBridge 并且特别是您创建的规则来调用它。

由于您要以编程方式创建规则和目标,您还需要使用AddPermission & the LambdaClient以编程方式授予此权限] 在你的 Java 申请中。

除其他外,AddPermission 允许您设置源 ARN,它是调用函数的 AWS 资源的 ARN。这将是 EventBridge 规则的 ARN。

这不是 必需的 但是,如果您没有指定来源,请注意其他账户可能会在其账户中配置资源以调用您的 Lambda 函数。因此,我建议始终设置源 ARN

将以上内容应用于您的代码,cloudWatchEventClient.putRule(putRuleRequest); 实际上会通过 ruleArn() 方法 return the ARN of the created rule in the PutRuleReponse,即

final PutRuleResponse response = cloudWatchEventClient.putRule(putRuleRequest);
final String ruleArn = response.ruleArn();

捕获此值后,创建并发送 AddPermissionRequest 以授予必要的权限。

这应该可以使用 AWS SDK for Java 2.x:

public void createCloudWatchRule(final LiveEventIdRelationInfo info) {
    ...
    final PutRuleRequest putRuleRequest = new PutRuleRequest()
            .withScheduleExpression(cronExpression)
            .withName(ruleName);

    final PutRuleResponse response = cloudWatchEventClient.putRule(putRuleRequest);
    final String ruleArn = response.ruleArn();

    final Target target = new Target()
            .withId(LAMBDA_TARGET_ID)
            .withArn(functionArn)
            .withInput(jsonString);
    final PutTargetsRequest putTargetsRequest = new PutTargetsRequest()
            .withRule(ruleName)
            .withTargets(target);
    cloudWatchEventClient.putTargets(putTargetsRequest);

    final AddPermissionRequest addPermissionRequest = new AddPermissionRequest()
        .withFunctionName(functionArn)
        .withStatementId("sid-" + LAMBDA_TARGET_ID)
        .withAction("lambda:InvokeFunction")
        .withPrincipal("events.amazonaws.com")
        .withSourceArn(ruleArn)
        .build();
    
    lambdaClient.addPermission(addPermissionRequest);
}

如果您将 AWS SDK 用于 Java 1.x,同样的概念也适用 - 语法会有细微差异,但交叉引用上述链接与 v1 文档,您将能够很容易地弄明白。