我的Lambda函数正在缓存S3函数调用的结果

时间:2018-02-09 16:48:45

标签: amazon-s3 lambda aws-lambda aws-sdk

我有一个lambda函数,它使用S3.listObjects返回目录列表。该列表有时(并非总是!)过时 - 它不包含最近上传的对象,并且具有旧的修改日期。

当我在本地运行相同的代码时,它总能正常工作。

显然是某种缓存,但我不明白...

以下是相关代码:

function listFiles() {
    return new Promise(function (resolve, reject) {
        const params = {
            Bucket: "XXXXX",
            Prefix: "YYYYY"
        };
        s3.listObjects(params, function (err, data) {
            if (err) reject(err);
            else resolve(data.Contents);            
        });
    })
}

2 个答案:

答案 0 :(得分:0)

这是由于Amazon S3 Data Consistency Model。 S3为PUT提供了写后读一致性,但是其他请求 - 包括listObjects最终是一致的,这意味着传播可能会有延迟。

答案 1 :(得分:0)

实际上,写后读的一致性仅需几秒钟即可解决。但是,这不是保证。几分钟后,亚马逊返回陈旧数据的可能性不大,但并非并非不可能,尤其是跨区域时。但是,您的客户端更有可能为该URL缓存先前的响应。

您可能会遇到lambda容器被重用的副作用。在较高级别的here中对此进行了说明。容器重用的结果之一是,重新调用lambda时,后台进程,临时文件和全局变量修改仍然存在。另一个article talking about how to guard

如果要将日志发送到cloudwatch日志,则可以将lambda的日志似乎附加到以前的日志流的末尾,而不是创建新的日志流,以确认容器正在被重用。 / p>

当您的lambda容器被重用时,处理程序函数外部的全局变量将被重用。例如,如果您在处理程序的末尾将日志调用的日志级别更改为DEBUG,则如果您的容器被重用,它将在同一日志级别处从处理程序的顶部开始。

如果您正在使用默认的s3客户端会话(看起来像是在使用),则此连接将保留在全局连接(单个)中。如果您的s3客户端连接被重用,则它可能会事先提取调用的缓存结果,我希望该连接在以后的调用中被重用。

避免这种情况的一种方法是指定If-None-Match请求标头。如果您要访问的对象的ETag在远端不匹配,您将获得新数据。您可以将其设置为您获得的最后一个Etag(将其存储在全局变量中),或者可以尝试设置一个完全随机的值-该值应充当缓存破坏者。但是,list_objects()似乎不接受If-None-Match标头。您可以尝试仅针对当前调用创建一个新的客户端会话。

article on recursive lambdas讨论了这个问题。