【问题标题】:Inconsistent results making API call from AWS Lambda从 AWS Lambda 调用 API 的结果不一致
【发布时间】:2018-10-25 14:37:02
【问题描述】:

让我提前为这个糟糕的代码道歉。我几乎拥有零节点经验,并且在后端使用 React 应用程序和 Elixir 编写我所有的 JS。我正在努力在 NodeJS 中编写一个正确的 Lambda 函数,并且基本上已经从谷歌搜索/SO/试验和错误等中拼凑出一些东西。

我正在做的事情如下:

  • 用户想要上传文件,因此他们将一些信息发送到后端。
  • 后端生成预签名密钥。
  • 前端将文件发送到 S3。
  • S3 触发事件并执行 Lambda
  • Lambda 现在检查 mimetype,如果它是错误文件,则会从 S3 存储桶中删除该文件,并向我的后端发出 DELETE API 调用,告诉它删除照片上传所属的行。

当我在 s3.deleteObject 调用中对后端进行 API 调用时,我遇到了困难,我得到的结果非常不一致。很多时候,它在同一个 Lambda 执行中背靠背发送两个删除请求。有时它甚至从不调用后端,只是运行并显示完整,而没有真正将任何内容记录到 Cloudwatch。

我的代码如下:

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

    const s3 = new aws.S3({apiVersion: '2006-03-01'});

    const fileType = require('file-type');

    const imageTypes = ['image/gif', 'image/jpeg', 'image/png'];

    const request = require('request-promise');

    exports.handler = async (event, context) => {
      // Get the object from the event and show its content type
      const bucket = event.Records[0].s3.bucket.name;
      const key = decodeURIComponent(
        event.Records[0].s3.object.key.replace(/\+/g, ' ')
      );

      const params = {
        Bucket: bucket,
        Key: key,
      };

      try {
        const {Body} = await s3.getObject(params).promise();

        const fileBuffer = new Buffer(Body, 'base64');
        const fileTypeInfo = fileType(fileBuffer);

        if (
          typeof fileTypeInfo !== 'undefined' &&
          fileTypeInfo &&
          imageTypes.includes(fileTypeInfo.mime)
        ) {
          console.log('FILE IS OKAY.');
        } else {
          await s3
            .deleteObject(params, function(err, data) {
              console.log('FILE IS NOT AN IMAGE.');
              if (err) {
                console.log('FAILED TO DELETE.');
              } else {
                console.log('DELETED ON S3.  ATTEMPTING TO DELETE ON SERVER.');

                const url =
                  `http://MYSERVERHERE:4000/api/event/${params.Key.split('.')[0]}`;

                const options = {
                  method: 'DELETE',
                  uri: url,
                };

                request(options)
                  .then(function(response) {
                    console.log('RESPONSE: ', response);
                  })
                  .catch(function(err) {
                    console.log('ERROR: ', err);
                  });
              }
            })
            .promise();
        }
        return Body;
      } catch (err) {
        const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
        console.log(message);
        throw new Error(message);
      }
    };

这几天让我发疯。感谢任何帮助解释为什么我会从这样的 Lambda 函数中得到意想不到的结果。

【问题讨论】:

    标签: node.js amazon-web-services amazon-s3 aws-lambda phoenix


    【解决方案1】:

    请在更新您的 else 部分后使用正确的 await 进行检查

    请尝试以下代码。

    exports.handler = async (event, context) => {
      // Get the object from the event and show its content type
      const bucket = event.Records[0].s3.bucket.name;
      const key = decodeURIComponent(
        event.Records[0].s3.object.key.replace(/\+/g, ' ')
      );
    
      const params = {
        Bucket: bucket,
        Key: key,
      };
    
      try {
        const {Body} = await s3.getObject(params).promise();
    
        const fileBuffer = new Buffer(Body, 'base64');
        const fileTypeInfo = fileType(fileBuffer);
    
        if (
          typeof fileTypeInfo !== 'undefined' &&
          fileTypeInfo &&
          imageTypes.includes(fileTypeInfo.mime)
        ) {
          console.log('FILE IS OKAY.');
        } else {
          await s3.deleteObject(params).promise(); //fail then catch block execute
            console.log('DELETED ON S3.  ATTEMPTING TO DELETE ON SERVER.');
    
            const url =
              `http://MYSERVERHERE:4000/api/event/${params.Key.split('.')[0]}`;
    
            const options = {
              method: 'DELETE',
              uri: url,
            };
    
            let response = await request(options); ////fail then catch block execute
            console.log(response);
          }
        return Body;
      } catch (err) {
        console.log(err);
        const message = `Error getting object ${key} from bucket ${bucket}. Make sure they exist and your bucket is in the same region as this function.`;
        console.log(message);
        throw new Error(message);
      }
    };
    

    【讨论】:

    • 谢谢。这解决了不一致的 API 调用,这是朝着正确方向迈出的重要一步,但由于某种原因永远无法解决 s3.deleteObject
    【解决方案2】:

    S3 删除操作最终在所有区域保持一致。

    因此与 AWS 一样(捕获的相关信息),

    • 进程删除现有对象并立即尝试读取它。在删除完全传播之前,Amazon S3 可能会返回已删除的数据。
    • 进程删除现有对象并立即列出其存储桶中的键。在删除完全传播之前,Amazon S3 可能会列出已删除的对象。

    参考:https://docs.aws.amazon.com/AmazonS3/latest/dev/Introduction.html#ConsistencyModel

    【讨论】:

    • 这似乎与这里考虑的问题无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    • 2020-09-10
    • 1970-01-01
    • 2017-06-10
    • 1970-01-01
    • 2022-10-23
    • 1970-01-01
    相关资源
    最近更新 更多