Как вы получаете объект HEAD от s3 в node.js?(работает в AWS лямбда) - PullRequest
0 голосов
/ 02 марта 2019

Я пытаюсь запустить лямбду, которая вставляет метаданные в мою базу данных каждый раз, когда объект помещается в мою корзину S3.

Поскольку я использую MongoDB, у меня есть код для сохранения соединений между базами данных между вызовами.У меня проблема в том, что я не могу получить метаданные.

Весь код для вставки в БД завершен, мне просто нужна помощь в получении метаданных из лямбды aws.

Вот мой код (в основном он скопирован с сайта MongoDB )

"use strict";
const MongoClient = require('mongodb').MongoClient;
const MONGODB_URI = 'mongodb://cam_writer:1%40kGM%26LL%26gA5y7NVk1cvl9@cluster0-shard-00-00-hlygq.mongodb.net:27017,cluster0-shard-00-01-hlygq.mongodb.net:27017,cluster0-shard-00-02-hlygq.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true'; // or Atlas connection string

var AWS = require('aws-sdk')
var s3 = AWS.S3()
let cachedDb = null;

function connectToDatabase (uri) {

  console.log('=> connect to database');

  if (cachedDb) {
    console.log('=> using cached database instance');
    return Promise.resolve(cachedDb);
  }



  return MongoClient.connect(uri)
    .then(client => {
      cachedDb = client.db('events');
      return cachedDb;
    });

}


function queryDatabase (db) {
  console.log('=> query database');

  return db.collection('detection_events').find({}).toArray()
    .then(() => { return { statusCode: 200, body: 'success' }; })
    .catch(err => {
      console.log('=> an error occurred: ', err);
      return { statusCode: 500, body: 'error' };
    });
}

function insertIntoDb (db, obj) {
  console.log('=> inserting data into db');

  return db.collection('detection_events').insertOne(obj)
}

module.exports.handler = (event, context, callback) => {

  context.callbackWaitsForEmptyEventLoop = false;

  console.log(event)

  var meta = {test : "test", "key": event}; // HOW DO I GET THE ACTUAL METADATA FOR THE EVENT?

  console.log('event: ', event);

  connectToDatabase(MONGODB_URI)
    .then(db => insertIntoDb(db, meta))
    .then(result => {
      console.log('=> returning result: ', result);
      callback(null, result);
    })
    .catch(err => {
      console.log('=> an error occurred: ', err);
      callback(err);
    });
};

Я знаю, что "событие", переданное в лямбду с помощью s3, не содержит метаданных.В python мне удалось получить метаданные с помощью boto3, я просто не знаю, как это сделать в node.js (не говоря уже о node.js в лямбда-выражении aws)

EDIT:

Итак, я обновил свой код согласно первому ответу ниже.Код теперь:

"use strict";
const MongoClient = require('mongodb').MongoClient;
const MONGODB_URI = 'mongodb://cam_writer:1%40kGM%26LL%26gA5y7NVk1cvl9@cluster0-shard-00-00-hlygq.mongodb.net:27017,cluster0-shard-00-01-hlygq.mongodb.net:27017,cluster0-shard-00-02-hlygq.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true'; // or Atlas connection string

const AWS = require('aws-sdk')
const s3 = new AWS.S3()
let cachedDb = null;

const connectToDatabase = uri => {

    console.log('=> connect to database');

    if (cachedDb) {
        console.log('=> using cached database instance');
        return Promise.resolve(cachedDb);
    }

    return MongoClient.connect(uri)
        .then(client => {
            cachedDb = client.db('events');
            return Promise.resolve(cachedDb);
        });

}

function insertIntoDb(db, obj) {
    console.log('=> inserting data into db');

    return db.collection('detection_events').insertOne(obj)
}

module.exports.handler = async (event) => {

    const db = await connectToDatabase(MONGODB_URI);

    //finally get the HEAD for the s3Object
    const head = await s3.headObject({
        Bucket: event.Records[0].s3.bucket.name,
        Key: event.Records[0].s3.object.key
    }).promise();

    var meta = head['Metadata']
    meta['bucket'] = event.Records[0].s3.bucket.name,
    meta['key'] = event.Records[0].s3.object.key
    console.log(meta)

    const result = await insertIntoDb(db, meta)

    console.log(result)
    return {
        statusCode: 201,
        body: JSON.stringify(result)
    }
};

Я запустил свой код, который вставляет кучу изображений в s3.Это дало около 25 соединений в mongodb, как я могу поддерживать низкое количество соединений с лямбдой?Я думал, что код, скопированный с сайта mongoDB, позволит мне сделать это

1 Ответ

0 голосов
/ 02 марта 2019

Поскольку вы используете событие S3, вы можете получить s3 корзину и key , получив доступ к event.Records[0].s3.bucket.name и event.Records[0].s3.object.key.Это может быть легко сделано с помощью следующего кода:

const params = {
  Bucket: event.Records[0].s3.bucket.name, 
  Key: event.Records[0].s3.object.key
 };
 s3.headObject(params, function(err, data) {
  if (err) {
    console.log(err, err.stack);
    return;
  }
  console.log(data)
});

Просто убедитесь, что вы поместили это в свой обратный вызов БД, иначе вы потеряете его.

Я бы оченьрекомендуем вам использовать async / await , поскольку вам не придется иметь дело со знаменитым адом обратного вызова .Вот переработанный код:

"use strict";
const MongoClient = require('mongodb').MongoClient;
const MONGODB_URI = 'mongodb://cam_writer:1%40kGM%26LL%26gA5y7NVk1cvl9@cluster0-shard-00-00-hlygq.mongodb.net:27017,cluster0-shard-00-01-hlygq.mongodb.net:27017,cluster0-shard-00-02-hlygq.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true'; // or Atlas connection string

const AWS = require('aws-sdk')
const s3 = AWS.S3()
let cachedDb = null;

const connectToDatabase = uri => {

  console.log('=> connect to database');

  if (cachedDb) {
    console.log('=> using cached database instance');
    return Promise.resolve(cachedDb);
  }

  return MongoClient.connect(uri)
    .then(client => {
      cachedDb = client.db('events');
      return Promise.resolve(cachedDb);
    });

}

function insertIntoDb (db, obj) {
  console.log('=> inserting data into db');

  return db.collection('detection_events').insertOne(obj)
}

module.exports.handler = async (event) => {

  const db = await connectToDatabase(MONGODB_URI);

  const result = await insertIntoDb(db, {
    bucket: event.Records[0].s3.bucket.name,
    key: event.Records[0].s3.object.key
  })

  console.log(result)

  //finally get the HEAD for the s3Object
   const head = await s3.headObject({
     Bucket: event.Records[0].s3.bucket.name,
     Key: event.Records[0].s3.object.key
   }).promise();

   console.log(head)

  return {
    statusCode: 201,
    body: JSON.stringify(result)
  }

};

Этого должно быть достаточно, чтобы вывести вас из строя.

РЕДАКТИРОВАТЬ : я рекомендую вам взглянуть на официальный NodeJS SDK , поскольку его документация довольно хороша

РЕДАКТИРОВАТЬ 2 : согласно предложению Майкла , если ваши файлы могут содержать пробелы, используйте вместо этого decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "))из event.Records[0].s3.object.key

EDIT 3 : Теперь, когда ваш код работает, вы сказали, что он добавляет «кучу» изображений в S3.S3 запустит столько событий, сколько вставлено изображений.Это означает, что N Lambdas будет ускоряться одновременно, поэтому каждый раз создается новое соединение MongoDB.

Один из возможных способов - ограничить число одновременных выполнений вашей функции Lambda меньшим, чтобы вы могли контролировать, какмногие соединения могут быть открыты одновременно.

Чтобы сделать это, перейдите на консоль Lambda и установите Concurrency на любой номер, который вы хотите (в приведенном ниже примере я использую 5).Этого должно быть достаточно, чтобы получить то, что вам нужно.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...