Лямбда-функция s3.getObject возвращает внутреннюю ошибку сервера

Этот код отлично работает локально, используя nodejs. Загрузка изображений с s3, запись в файл.

Однако в Lambda (с использованием nodejs 8.10) я получаю «Внутреннюю ошибку сервера» при тестировании функции с этим в журналах:

«Выполнение не выполнено из-за ошибки конфигурации: неверный ответ прокси-сервера Lambda»

Я использую ответ лямбда-прокси в обратном вызове, но очевидно, что какая-то ошибка AWS SDK с S3 не улавливается.

У меня есть настройка роли с полным доступом S3, к которому имеет доступ Lambda.

Чего мне не хватает в моей первой лямбда-функции? Документы и учебные пособия, которым я следовал правильно, и это не работает.

const async = require('async')
const aws = require('aws-sdk')
const fs = require('fs')
const exec = require('child_process').exec

const bucket = 'mybucket'
const s3Src = 'bucket_prefix'
const s3Dst = 'new_prefix'
const local = `${__dirname}/local/`
aws.config.region = 'us-west-2'
const s3 = new aws.S3()

exports.handler = async (event, context, callback) => {
    const outputImage = 'hello_world.png'
    const rack = JSON.parse(event.body)
    const images = my.images

    async.waterfall([
            function download(next) {
                let downloaded = 0
                let errors = false
                let errorMessages = []

                for (let i = 0; i < images.length; i++) {
                    let key = `${s3Src}/${images[i].prefix}/${images[i].image}`,
                        localImage = `${local}${images[i].image}`

                    getBucketObject(bucket, key, localImage).then(() => {
                        ++downloaded
                    if (downloaded === images.length) { // js is non blocking, need to check if all images have been downloaded. If so, then go to next function
                        if (errors) {
                            next(errorMessages.join(' '))
                        } else {
                            next(null)
                        }
                    }
                }).catch(error => {
                    errorMessages.push(`${error} - ${localImage}`)
                    ++downloaded
                    errors = true
                })
            }

            function getBucketObject(bucket, key, dest) {
                return new Promise((resolve, reject) => {
                    let ws = fs.createWriteStream(dest)

                    ws.once('error', (err) => {
                        return reject(err)
                    })

                    ws.once('finish', () => {
                        return resolve(dest)
                    })

                    let s3Stream = s3.getObject({
                        Bucket: bucket,
                        Key: key
                    }).createReadStream()

                    s3Stream.pause() // Under load this will prevent first few bytes from being lost

                    s3Stream.on('error', (err) => {
                        return reject(err)
                    })

                    s3Stream.pipe(ws)
                    s3Stream.resume()
                })
            }
        }
    ], err => {
        if (err) {
            let response = {
                "statusCode": 400,
                "headers": {
                    "my_header": "my_value"
                },
                "body": JSON.stringify(err),
                "isBase64Encoded": false
            }
            callback(null, response)
        } else {
            let response = {
                "statusCode": 200,
                "headers": {
                    "my_header": "my_value"
                },
                "body": JSON.stringify(`<img src="${local}${outputImage}" />`),
                "isBase64Encoded": false
            }
            callback(null, response)
        }
    }
)

}


person Zelf    schedule 24.09.2018    source источник
comment
Я имею в виду, что вам определенно нужно переписать свой код. И у вас неправильное представление о времени выполнения 8.10. Вы хотите использовать async/await с try/catch, но вы все еще придерживаетесь обратных вызовов. И вы должны разделить эту сложную функцию на две части.   -  person Nikolay Vetrov    schedule 25.09.2018


Ответы (2)


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

Кстати, должны ли ваши функции в async.waterfall быть разделены запятой, как две задачи?

person michail_w    schedule 24.09.2018

Локально я запускал nodejs 10.10, а лямбда в настоящее время — 8.10. Это большая часть, я уверен. В конце концов мне пришлось удалить async. Мне пришлось переместить функцию getBucketObject из водопада. Как только я сделал эти настройки, он начал работать. И еще одна проблема заключалась в том, что загруженные изображения необходимо было помещать в каталог «/ tmp».

const aws = require('aws-sdk')
const async = require('async')
const fs = require('fs')

const bucket = 'mybucket'
const s3Src = 'mys3src'
const local = '/tmp/'
aws.config.region = 'us-west-2'
const s3 = new aws.S3()

exports.handler = (event, context, callback) => {
    const outputImage = 'hello_world.png'

    async.waterfall([
            function download(next) {
                let downloaded = 0,
                    errorMessages = []

                for (let i = 0; i < event['images'].length; i++) {
                    let key = `${s3Src}/${event['images'][i]['prefix']}/${event['images'][i]['image']}`,
                        localImage = `${local}${event['images'][i]['image']}`

                    getBucketObject(bucket, key, localImage).then(() => {
                        downloaded++

                        if (downloaded === event['images'].length) {
                            if (errorMessages.length > 0) {
                                next(errorMessages.join(' '))
                            } else {
                                console.log('All downloaded')
                                next(null)
                            }
                        }
                    }).catch(error => {
                        downloaded++
                        errorMessages.push(`${error} - ${localImage}`)

                        if (downloaded === event['images'].length) {
                            next(errorMessages.join(' '))
                        }
                    })
                }
            }
        ], err => {
            if (err) {
                console.error(err)
                callback(null, {
                    "statusCode": 400,
                    "body": JSON.stringify(err),
                    "isBase64Encoded": false
                })
            } else {
                console.log('event image created!')
                callback(null, {
                    "statusCode": 200,
                    "body": JSON.stringify(`<img src="${local}${outputImage}" />`),
                    "isBase64Encoded": false
                })
            }
        }
    )
}

function getBucketObject(bucket, key, dest) {
    return new Promise((resolve, reject) => {
        let ws = fs.createWriteStream(dest)

        ws.once('error', (err) => {
            return reject(err)
        })

        ws.once('finish', () => {
            return resolve(dest)
        })

        let s3Stream = s3.getObject({
            Bucket: bucket,
            Key: key
        }).createReadStream()

        s3Stream.pause() // Under load this will prevent first few bytes from being lost

        s3Stream.on('error', (err) => {
            return reject(err)
        })

        s3Stream.pipe(ws)
        s3Stream.resume()
    })
}
person Zelf    schedule 25.09.2018