从 Lambda 函数(无服务器 Nodejs)内部调用 S3.waitFor()
函数时遇到问题。我尝试使用 S3.putObject()
从一个 Rest api 将文件异步写入 Amazon S3,并使用 S3.waitFor()
从另一个 Rest api 轮询结果文件,以查看写入是否已准备好/完成。
请参阅以下代码片段:
...
S3.waitFor('objectExists', {
Bucket: bucketName,
Key: fileName,
$waiter: {
maxAttempts: 5,
delay: 3
}
}, (error, data) => {
if (error) {
console.log("error:" + JSON.stringify(error))
} else {
console.log("Success")
}
});
...
给定有效bucketName和无效文件名,当代码在我的本地测试脚本中运行时,它会在15秒(3秒x 5次重试)后返回错误,并生成如下结果:
error: {
"message": "Resource is not in the state objectExists",
"code": "ResourceNotReady",
"region": null,
"time": "2018-08-03T06:08:12.276Z",
"requestId": "AD621033DCEA7670",
"extendedRequestId": "JNkxddWX3IZfauJJ63SgVwyv5nShQ+Mworb8pgCmb1f/cQbTu3+52aFuEi8XGro72mJ4ik6ZMGA=",
"retryable": true,
"statusCode": 404,
"retryDelay": 3000
}
同时,当它在AWS lambda函数中运行时,它直接返回结果,如下所示:
error: {
"message": "Resource is not in the state objectExists",
"code": "ResourceNotReady",
"region": null,
"time": "2018-08-03T05:49:43.178Z",
"requestId": "E34D731777472663",
"extendedRequestId": "ONMGnQkd14gvCfE/FWk54uYRG6Uas/hvV6OYeiax5BTOCVwbxGGvmHxMlOHuHPzxL5gZOahPUGM=",
"retryable": false,
"statusCode": 403,
"retryDelay": 3000
}
正如您所看到的,两者之间的 retryable 和 statusCode 值是不同的。
在amba上,当文件不存在时,它似乎总是得到statusCode 403。在我的本地上,一切都按预期运行(每 3 秒重试 5 次并收到状态代码 404)。
我想知道这是否与 IAM 角色有关。这是我的 serverless.yml 中的 IAM 角色语句设置:
iamRoleStatements:
- Effect: "Allow"
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
- "sns:Publish"
- "sns:Subscribe"
- "s3:*"
Resource: "*"
如何让它通过 lambda 函数工作? 预先感谢您!
最佳答案
事实证明,关键在于如何为存储桶及其下的所有对象设置 IAM 角色。
基于 AWS 文档 here ,它指出 S3.waitFor()
依赖于底层 S3.headObject()
。
Waits for the objectExists state by periodically calling the underlying S3.headObject() operation every 5 seconds (at most 20 times).
同时,S3.headObject()
本身依赖于 HEAD 对象 API,该 API 具有 AWS 文档 here 中所述的以下规则:
You need the s3:GetObject permission for this operation. For more information, go to Specifying Permissions in a Policy in the Amazon Simple Storage Service Developer Guide. If the object you request does not exist, the error Amazon S3 returns depends on whether you also have the s3:ListBucket permission.
- If you have the s3:ListBucket permission on the bucket, Amazon S3 will return a HTTP status code 404 ("no such key") error.
- if you don’t have the s3:ListBucket permission, Amazon S3 will return a HTTP status code 403 ("access denied") error.
这意味着我需要将 s3:ListBucket
Action 添加到包含对象的 Bucket 资源中,以便在对象不存在时能够获取响应 404。
因此,我配置了 cloudformation AWS::IAM::Policy 资源,如下所示,其中专门针对存储桶本身(即:S3FileStorageBucket)添加了 s3:Get*
和 s3:List*
操作。
"IamPolicyLambdaExecution": {
"Type": "AWS::IAM::Policy",
"DependsOn": [
"IamRoleLambdaExecution",
"S3FileStorageBucket"
],
"Properties": {
"PolicyName": { "Fn::Join": ["-", ["Live-RolePolicy", { "Ref": "environment"}]]},
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect":"Allow",
"Action": [
"s3:Get*",
"s3:List*"
],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "S3FileStorageBucket"
}
]
]
}
},
{
"Effect":"Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "S3FileStorageBucket"
},
"/*"
]
]
}
},
...
现在,我已经能够执行 S3.waitFor()
只需一次 API 调用即可轮询存储桶下的文件/对象,并且仅在准备就绪时获取结果,或者在特定超时后资源未准备好时抛出错误。
这样,客户端实现就会简单得多。因为它不必自己实现 poll。
希望有人觉得它有用。谢谢。
关于node.js - AWS Lambda 中的 Amazon S3 waitFor(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51667179/