NodeJS Amazon AWS SDK S3 客户端间歇性停止工作

问题描述 投票:0回答:1

我有 NodeJS Express Web 服务器,可以提供来自 AWS S3 的文件。大多数时候,这个确切的代码可以正常工作,并为生产中具有大量请求的各种应用程序提供文件。 NodeJS Web 服务器在 docker swarm 服务器上的多个节点上运行。

大约 2-3 周后,此功能将停止工作。 S3Client 没有响应

GetObjectCommand
,没有返回错误或任何东西。仅在重新启动 NodeJS Docker 容器后,此操作才会再次开始工作。

我阅读了 S3 SDK 文档,其中指出 SDK 将自动重试

每个 AWS 开发工具包都实现自动重试逻辑。

问题:

  • 我们怎样才能使这段代码更具弹性并且不需要重新启动?
  • 错误处理是否正确?我想知道为什么在这种情况下似乎没有任何响应或根本没有返回错误。
  • 是否需要配置重试设置

NodeJS 版本:node:lts-alpine 模块:@aws-sdk/client-s3

控制器

AWS 控制器

const consoleLogger = require('../logger/logger.js').console;
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');

const config = {
  "credentials": {
    "accessKeyId": "example",
    "secretAccessKey": "example"
  },
  "endpoint": "example",
  "sslEnabled": true,
  "forcePathStyle": true
}

const s3client = new S3Client(config);

const awsCtrl = {};

awsCtrl.getObject = async (key) => {

  // Get object from Amazon S3 bucket
  let data;
  try {
    // Data is returned as a ReadableStream
    data = await s3client.send(new GetObjectCommand({ Bucket: "example", Key: key }));
    console.log("Success", data);
  } catch (e) {
    consoleLogger.error("AWS S3 error: ", e);
    const awsS3Error = {
      name: e.name || null,
      status: e.$metadata.httpStatusCode || 500
    };
    throw awsS3Error;
  }

  return data;

}

module.exports = awsCtrl;

文件控制器

const queryString = require('query-string');
const consoleLogger = require('../logger/logger.js').console;
const httpCtrl = require('./http.ctrl');
const jwtCtrl = require('./jwt.ctrl');
const awsCtrl = require('./aws.ctrl');

filesCtrl.deliverFile = async (req, res) => {
  /* Get object from AWS S3 */
  let fileObjectStream;
  try {
    fileObjectStream = await awsCtrl.getObject(filePath);
  } catch (e) {
    consoleLogger.error(`Unable to get object from AWS S3`, e);
    if (e.status && e.status === 404) {
      result.error = `Not found`;
      result.status = 404;
      return res.status(result.status).json(result);
    }
    return res.status(e.status || 500).json(result);
  }

  const filename = lookupResponse.data.filename;

  // Set response header: Content-Disposition
  res.attachment(filename);
  // API response object stream download to client
  return fileObjectStream.Body.pipe(res);

}

API

const express = require('express');
const router = express.Router();
const filesCtrl = require('../../controllers/files.ctrl');
const filesValidation = require('../validation/files');

router.get('/:fileId', [filesValidation.getFile], (req, res, next) => {

  return filesCtrl.deliverFile(req, res);

});
node.js amazon-web-services amazon-s3
1个回答
0
投票

我们使用 AWS Lambda 遇到了一个非常类似的问题,如果我们运行超过 5 或 6 个并发 Lambda,从 S3 读取 Lambda 就会死掉,没有错误,没有跟踪,也没有回退(= SQS 上的死信,这会触发拉姆达)。 非常令人沮丧和“危险”,因为我们没有任何迹象表明该事件没有得到正确处理。

希望您已经解决了这个问题,但由于 AWS 尚未修复此问题,因此可能对其他人有帮助...

从 AWS 支持中我们得到了在每次调用时重新实例化客户端的建议,因此您的代码应该类似于:

const consoleLogger = require('../logger/logger.js').console;
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');

const config = {
  "credentials": {
    "accessKeyId": "example",
    "secretAccessKey": "example"
  },
  "endpoint": "example",
  "sslEnabled": true,
  "forcePathStyle": true
}

const awsCtrl = {};

awsCtrl.getObject = async (key) => {
  const s3client = new S3Client(config); // <== new instance of the client
  // Get object from Amazon S3 bucket
  let data;
  try {
    // Data is returned as a ReadableStream
    data = await s3client.send(new GetObjectCommand({ Bucket: "example", Key: key }));
    data.Body.on('finished', () => s3Client.destroy()); // <== destroy it once used
    console.log("Success", data);
  } catch (e) {
    consoleLogger.error("AWS S3 error: ", e);
    const awsS3Error = {
      name: e.name || null,
      status: e.$metadata.httpStatusCode || 500
    };
    throw awsS3Error;
  }

  return data;

}

module.exports = awsCtrl;

这当然会对性能造成影响,但是您可能会发现调整http代理的其他建议解决方法并不能保证有效,因为无论如何您迟早都会达到上限...

© www.soinside.com 2019 - 2024. All rights reserved.