未从Lambda随机触发Cloudfront createInvalidation

问题描述

从AWS Lambda创建Cloudfront失效时,我遇到了问题。

我的情况很简单:我设置了一个Lambda处理程序,由特定的S3对象创建删除操作触发,以使Cloudfront发行版上的缓存版本无效。这是使用nodejs编写的功能代码

const AWS = require('aws-sdk');

exports.handler = async function (event,context) {
    const cloudFront = new AWS.CloudFront();

    const invalidationParams = {
        distributionId: "XXXX",InvalidationBatch: {
            CallerReference: Date.Now().toString(),Paths: {
                Quantity: 2,Items: [
                    "/index.html","/service-worker.js"
                ]
            }
        }
    };

    cloudFront.createInvalidation(invalidationParams,(error,data) => {
        if (error) {
            console.log(error,error.stack);
        } else {
            console.log("Invalidation results",data);
        }
    });
};

如您所见,没有什么太复杂的。 现在,在大多数情况下,处理程序在执行任何操作时都没有做任何事情,我正在观察日志,除了请求ID和开始和结束时间戳记之外,什么都没有打印,甚至没有Cloudfront错误,这让我想知道发生了什么。 在连续执行四到五次手动测试之后,会正确创建一个失效,但是日志不会报告该失效。再点火一次,然后打印上次运行的无效结果。我觉得这很奇怪和令人困惑。

从上下文和Lambda代码来看,我可能会缺少一些东西吗?

谢谢。

解决方法

这是因为有Lambda运行时模型。当您使用异步函数作为处理程序时,Lambda执行在返回时被视为“完成”(返回的Promise已结算)。在您的代码中,创建了一个失效,但是处理程序函数在失效完成之前返回

当Lambda被视为“完成”时,它冻结了该函数,并且它不会等待createInvalidation完成。有时起作用但有时不起作用的原因是,在Lambda冻结功能和失效请求之间存在竞争条件。我写了article with a more in-depth exlanation

解决方案很简单:在完成处理程序之前,等待createInvalidation完成:

const AWS = require('aws-sdk');

exports.handler = async function (event,context) {
    const cloudFront = new AWS.CloudFront();

    const invalidationParams = {
        DistributionId: "XXXX",InvalidationBatch: {
            CallerReference: Date.now().toString(),Paths: {
                Quantity: 2,Items: [
                    "/index.html","/service-worker.js"
                ]
            }
        }
    };

    await cloudFront.createInvalidation(invalidationParams).promise();

    // by the time the handler reaches this point the invalidation made it through
};