0

此代码使用 nodejs 在本地运行良好。图片从 s3 下载,写入文件。

但是,在 Lambda(使用 nodejs 8.10)中,在日志中使用此功能测试函数时出现“内部服务器错误”:

“由于配置错误,执行失败:Lambda 代理响应格式错误”

我在回调中使用了 lambda 代理响应,但显然 S3 的一些 AWS SDK 错误没有被捕获。

我确实有一个角色设置,具有 Lambda 可以访问的 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)
        }
    }
)

}

4

2 回答 2

1

应始终将响应发送到回调函数。您的代码仅在错误时发送响应。这就是 Lambda 执行器认为您的代码失败的原因。

顺便说一句 - 你在 async.waterfall 中的函数是否应该用逗号分隔,作为两个任务?

于 2018-09-24T23:10:22.980 回答
0

在本地,我一直在运行 nodejs 10.10,而 lambda 目前是 8.10。我敢肯定,这是很大一部分。最后我不得不删除异步。我不得不将 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()
    })
}
于 2018-09-25T02:49:45.903 回答