如何使用Node.JS检查S3存储桶近X天是否有指定文件上传
问题1:Node.js实现S3指定文件上传状态校验的实现方式
直接用AWS SDK for JavaScript v3实现即可,核心逻辑是拉取S3单个文件的元数据做时间比对,不要用遍历桶的接口查单个文件,效率极低还容易出问题。
首先安装依赖:npm install @aws-sdk/client-s3 @aws-sdk/client-lambda
核心校验逻辑代码如下,可以直接放到Lambda或者Node.js服务中运行:
const { S3Client, HeadObjectCommand } = require("@aws-sdk/client-s3"); const { LambdaClient, InvokeCommand } = require("@aws-sdk/client-lambda"); // 初始化客户端,替换为你的资源所在AWS区域,比如ap-southeast-1 const s3Client = new S3Client({ region: "your-aws-region" }); const lambdaClient = new LambdaClient({ region: "your-aws-region" }); /** * 校验指定S3文件90天内是否有上传,无上传则触发缓存加载Lambda * @param {string} bucketName S3桶名 * @param {string} fileKey 待校验文件的完整路径key * @param {string} lambdaFunctionName 缓存加载Lambda的函数名 */ async function checkFileAndTriggerCache(bucketName, fileKey, lambdaFunctionName) { const ninetyDaysTimestamp = Date.now() - 90 * 24 * 60 * 60 * 1000; let needTrigger = false; try { // 直接拉取文件元数据,不用下载文件,性能最高 const fileMeta = await s3Client.send(new HeadObjectCommand({ Bucket: bucketName, Key: fileKey })); // 比对最后修改时间,早于90天前则需要触发 if (fileMeta.LastModified.getTime() < ninetyDaysTimestamp) { needTrigger = true; } } catch (err) { // 文件不存在直接判定需要触发 if (err.name === "NotFound") { needTrigger = true; } else { // 权限错误、网络错误等直接抛出,避免误触发 throw err; } } if (needTrigger) { // 异步触发Lambda,不用等待执行结果 await lambdaClient.send(new InvokeCommand({ FunctionName: lambdaFunctionName, Payload: Buffer.from(JSON.stringify({ source: "s3-90day-check", bucket: bucketName, key: fileKey })), InvocationType: "Event" })); return { status: "lambda_triggered", msg: "file not uploaded in 90 days, cache reload started" }; } return { status: "skip", msg: "file uploaded within 90 days, cache is valid" }; }
注意:不要用
listObjectsV2接口遍历桶查找指定文件,这个接口是用来批量列对象的,查单个文件纯属浪费请求额度,文件量大的时候还要处理分页逻辑,容易出bug。HeadObject是查询单个文件元数据的官方标准接口,一次请求就能拿到结果,成本最低。
落地时需要注意权限配置:
- 跑这段代码的身份(IAM角色/用户)只需要配两个最小权限:目标存储桶的
s3:HeadObject权限,目标缓存加载Lambda的lambda:InvokeFunction权限,不要给多余权限。 - 触发Lambda时固定用
InvocationType: 'Event'走异步触发,不用等Lambda执行完返回,避免校验逻辑超时。
问题2:Cron Job巡检的可行性与更优方案
首先给结论:自托管Cron Job巡检是可行的,但不是最优解,存在明显短板。
自托管Cron的问题
- 有单点故障风险:跑Cron的服务器挂了就会漏校验,要自己做高可用,运维成本高。
- 凭证管理麻烦:要自己维护AK/SK,定期轮换,漏换就会导致校验逻辑失效。
- 精度和成本难平衡:巡检间隔设短了,会产生大量无效的S3 API请求,增加成本;设长了,文件过了90天窗口期后要等很久才会被加载到缓存,影响业务。
托管式定时巡检方案(适合文件量小的场景)
如果要走定时巡检的路线,别自己搭Cron,直接用EventBridge Scheduler(原CloudWatch Events)定时触发一个跑上述校验逻辑的Lambda即可,是Cron方案的托管升级版:
- 不用管服务器运维,AWS本身保障服务可用性,调度精度最高到1分钟。
- 自带重试、死信队列能力,不会因为单次请求失败漏校验。
- Lambda直接绑定IAM角色就行,不用自己管凭证轮换。
如果待校验文件只有几十到几百个,每天触发一次巡检完全够用,实现成本极低。
更优的事件驱动+精准调度方案(适合文件量大的场景)
如果待校验文件量级大(上千甚至更多),定时全量巡检的成本会很高,推荐用下面的方案,几乎没有无效请求,精度也最高:
- 保留现有的S3上传事件直接触发Lambda写缓存的流程,这部分是实时的,上传完成立刻同步缓存,无延迟。
- 每次上传事件触发Lambda写缓存时,同步在EventBridge Scheduler里创建一个90天后触发的一次性调度任务,任务内容就是跑上述的单文件校验逻辑:到点后检查这个文件的最后上传时间,如果确实90天内没有新上传,就主动触发加载缓存的Lambda,再创建下一个90天的一次性调度;如果90天内已经有新上传触发过缓存同步,直接删掉这个过期的调度任务就行。
- 额外给缓存条目加90天TTL做兜底,极端情况调度任务丢了,缓存过期时也会触发回源加载,不会出现缓存空窗。
这个方案没有全量巡检的空跑开销,每个文件只会在刚好到90天窗口期的时候做一次校验,比定时全量扫省90%以上的API成本,也不会有巡检间隔带来的同步延迟。
内容的提问来源于stack exchange,提问作者Aravind
相关产品推荐
相关产品推荐

