рекурсивная лямбда-функция никогда не запускается - PullRequest
1 голос
/ 21 сентября 2019

Я недостаточно знаком с node.js или lambda, чтобы увидеть очевидное решение моей дилеммы.Я пишу некоторые утилиты для лямбды, чтобы манипулировать изображениями в корзине S3 и делать их доступными через GatewayAPI для переадресации вызовов.

ФОНОВЫЕ ДЕТАЛИ: Одна из утилит, которую я имею, получает информацию headObject, такую ​​как mtime,размер и метаданные.Сами изображения, вероятно, будут поступать различными способами, и я не всегда буду контролировать добавление к ним метаданных, когда они будут получены / созданы.Но мне это не нужно до тех пор, пока в веб-интерфейсе не будет необходимости просматривать детали изображения.И когда я делаю это, я использую вместо этого миниатюру, поэтому я создал лямбда-сценарий, запускаемый при создании события (и также имею запасной вариант его через gatewayAPI), который создаст миниатюру (либо при первой загрузке изображения на S3).или всякий раз, когда я выполняю вызов шлюза CreateThumbbnail), в это время он добавляет метаданные к миниатюре изображения с такими вещами, как исходный образ mimetype, ширина и высота пикселя.

Что бы я хотел иметь,заключается в создании 'GetObjectInfo', который сначала извлекает данные headObject, а затем проверяет, является ли указанная корзина корзиной с соответствующими файлами миниатюр или нет.(например, если это миниатюрный объект или нет). Если это не миниатюра, я хочу затем извлечь или, по крайней мере, попытаться извлечь headObject для связанного файла миниатюр и прикрепить метаданные файла миниатюр.(если миниатюра существует) на данные из исходного запроса заголовка перед возвратом информации.

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

Метод в моем классе:

getHeadObject(bucket,object,callback) {
    console.log(bucket, "CLASS-head#1")
    this.s3.headObject({"Bucket":bucket,"Key":object}, function(err,data){
        console.log(bucket, "CLASS-head#2")
        callback(err,data)
    })
}
getObjectInfo(bucket,object,callback) {
    let scope = this
    console.log(bucket,"CLASS-object#1")
    this.getHeadObject(bucket,object,function(err,data) {
        console.log(bucket,"CLASS-object#2")
        if(err)
            callback(err,data)
        else
            callback(null,data)
    })
}

Лямбда-код, который вызывает его рекурсивно:

var cInst = new myClass()
cInst.getObjectInfo(srcBucket,filePath,function(err,data) {
    if(data.status == 1) {              // if parent request success
                                        // if parent is not thumbnail
        if(srcBucket != THUMB_BUCKET) { // see if a thumbnail exists
            let thumbPath = myClass.getThumbPath(srcBucket,userId,directory,targetObject)
            console.log('---- thumbPath', thumbPath)
            cInst.getObjectInfo(THUMB_BUCKET,thumbPath, function(err,thumbData) {
                console.log("thumbData #1",thumbData)
                if(thumbData.status == 1) { // thumbnail exists
                    console.log("thumbData")
                }
            })
        }
        context.succeed(myClass.createResponse(1, data, api))
    } else {
        context.fail(myClass.createResponse(data.status, data, api))
    }
})

Первый вызов народительский элемент см.

{bucket} "CLASS-object#1"
{bucket} "CLASS-head#1"
{bucket} "CLASS-head#2"
{bucket} "CLASS-object#2"

, на втором я вижу только:

image-thumbnails "CLASS-object#1"
image-thumbnails "CLASS-head#1"

(getThumbPath - это просто статическая служебная функция, которая строит путь миниатюры на основе параметров, связанных с исходнымфайл. Он уже протестирован как работающий и создает что-то вроде {original-bucket-name} / {userid} / {subdirectory} / {file-basename_150x150.jpg} для любого заданногоimage - я подтвердил, что в этом случае миниатюра существует и соответствует пути, возвращенному getThumbPath, и у acl, по-видимому, есть разрешение на чтение корзины и объекта)

ОБНОВЛЕНИЕ: больше странностей

Я попытался установить разрешения для публичного чтения на миниатюре, и это сработало.Поэтому я начал возиться с ACL.Пока я все еще тестирую, я просто дал роль сценариям с полными разрешениями S3.

Но я заметил, что он работает и работает с перебоями.Один раз это завершается, в следующий раз - нет.WTF здесь происходит?

1 Ответ

0 голосов
/ 21 сентября 2019

Держу пари, что это самая распространенная проблема, с которой люди сталкиваются при использовании Node.js с Lambda.

Когда лямбда Node.js достигает конца основного потока, он завершает все остальные потоки.Когда он достигает конца обработчика, он останавливает все выполняющиеся параллельные обещания или асинхронные вызовы.

Чтобы убедиться, что лямбда не завершает преждевременно эти потоки, дождитесь завершения этих обещаний, используя await.

В вашем случае сработает следующее: заверните любые async вызовы в обещание, а затем await их.

await new Promise(async (resolve, reject) => {
    cInst.getObjectInfo(srcBucket,filePath,function(err,data) {
        if(data.status == 1) {              
            if(srcBucket != THUMB_BUCKET) {
                ...
                ...
                await new Promise((resolve2, reject2) => {
                    cInst.getObjectInfo(THUMB_BUCKET,thumbPath, function(err,thumbData) {
                        ...
                        ...
                        resolve2();
                    })
                })

            }
            context.succeed(myClass.createResponse(1, data, api))
            resolve();
        } else {
            context.fail(myClass.createResponse(data.status, data, api))
            reject();
        }
    })
})
...