Попытка проверить, существует ли элемент корзины s3 во вложенных асинхронных программах - PullRequest
2 голосов
/ 13 мая 2019

У меня есть функция Serverless Lambda, которая в ответ на событие S3 s3:ObjectCreated пытается проверить, существует ли отдельный элемент в корзине S3, используя следующий бит кода с использованием AWS JavaScript SDK:

exports.somethingSomeSomething = async (event) => {

  event.Records.forEach(async (record) => {

    let tst = await s3.headObject({
      Bucket: "mybucket",
      Key: "something.gz"
    }).promise()

    console.log(tst)
  })

};

Я довольно устал от обещаний в JS, поэтому я не уверен, почему этот фрагмент кода не работает. Для справки он просто умирает, ничего не выводя.

Однако следующее работает :

exports.somethingSomething = async (event) => {


    let tst = await s3.headObject({
      Bucket: "mybucket",
      Key: "something.gz"
    }).promise()

    console.log(tst)
    console.log("RED")

};

Как заставить начальный бит кода работать и что я делаю не так?

1 Ответ

1 голос
/ 13 мая 2019

Это потому, что ваш код async, но функция, переданная в ваш цикл forEach, также async, поэтому у вас есть функция async, вызывающая другой фрагмент кода async, поэтому вы теряете контроль над поток. Все, что находится внутри forEach, будет работать (хотя все, что после forEach будет работать раньше, чем то, что находится внутри forEach), но оно будет выполняться асинхронно, и вы не сможете отслеживать его выполнение.

Но если код, как я уже сказал, запустится, почему вы не видите результаты?

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

У вас есть два варианта:

Самый простой - захватить первый элемент в массиве Records, поскольку события s3 отправляют одно и только одно событие за вызов. Это массив, потому что работает AWS (общий интерфейс для всех событий). В любом случае, ваш forEach не использует ничего из объекта Record, но, тем не менее, если вы хотите использовать какие-либо его свойства, просто укажите ссылку на 0-ю позицию следующим образом:

exports.somethingSomeSomething = async (event) => {
    const record = event.Records[0]

    //do something with record

    const tst = await s3.headObject({
        Bucket: "mybucket",
        Key: "something.gz"
    }).promise()

    console.log(tst)
};

Если вы все еще хотите использовать цикл for для итерации записей (хотя, опять же, это не нужно для событий s3), используйте вместо этого цикл for of:

exports.somethingSomeSomething = async (event) => {
    for (const record of event.Records) {
        // do something with record
        const tst = await s3.headObject({
            Bucket: "mybucket",
            Key: "something.gz"
        }).promise()
        console.log(tst)
    }
};

Поскольку for of является просто обычным циклом, он будет использовать async из функции, в которой он выполняется, поэтому await совершенно допустимо внутри него.

Подробнее о асинхронных / ожидающих и для ... 1034 *

...