Lambda使用大图像产生空缓冲区错误

时间:2016-10-13 16:52:48

标签: node.js amazon-web-services aws-lambda

当我尝试发送大图像时,我在Lambda中遇到了这个代码的问题。 我发送了一堆图像,并调整大小并创建了几个不同的大小,如数组SIZES所示。

我的Lambda配置处于高位,最大内存(1536mb)最大超时5mim

当大图像上传时出现问题。我搜索了所有互联网,但我找不到解决方案。

错误

Unhandled rejection Error: Stream yields empty buffer
at Socket.<anonymous> (/var/task/node_modules/gm/lib/command.js:57:17)
at emitNone (events.js:72:20)
at Socket.emit (events.js:166:7)
at endReadableNT (_stream_readable.js:905:12)
at nextTickCallbackWith2Args (node.js:437:9)
at process._tickDomainCallback (node.js:392:17)

**这是代码。*

var gm = require('gm').subClass({
        imageMagick: true
    }),
    aws = require('aws-sdk'),
    async = require('async'),
    fs = require('fs'),
    promise = require('bluebird'),
    request = require('request').defaults({
        encoding: null
    });

var BUCKET = "myBucket",
    FOLDER = 'photos/',
    s3 = new aws.S3({
        accessKeyId: 'myKeyId',
        secretAccessKey: 'mySecretKey'
    }),
    SIZES = [{
        type: 'original',size: 1080,mark: false,hide: true
    }, {
        type: 'thumb',size: 120, mark: false, hide: false
    }, {
        type: 'thumb',size: 240, mark: false, hide: false
    }, {
        type: 'thumb',size: 360, mark: false, hide: false
    }, {
        type: 'card',size: 350 ,mark: false, hide: false
    }, {
        type: 'full',size: 360, mark: true, hide: false
    }, {
        type: 'full',size: 540, mark: true, hide: false
    }, {
        type: 'full',size: 720, mark: true, hide: false
    }, {
        type: 'full',size: 900, mark: true, ide: false
    }, {
        type: 'full',size: 1080, mark: true, hide: false
    }];

var service = {
    s3: {
        download: function(bucket, key) {
            return new promise(function(resolve, reject) {
                s3.getObject({
                    Bucket: bucket,
                    Key: key
                }, function(err, data) {
                    if (err) {
                        reject(err);
                    } else {
                        resolve(data);
                    }
                });

            });
        },
        upload: {
            async: function(photo, bucket, key, content_type, private) {
                return new promise(function(resolve, reject) {
                    s3.putObject({
                        Bucket: bucket,
                        Key: key,
                        Body: photo,
                        ContentType: content_type,
                        ACL: private ? 'private' : 'public-read'
                    }, function(err, data) {
                        if (err) {
                            reject(err)
                        } else {
                            resolve(key);
                        }
                    });
                });
            }
        }
    },
    watermark: {
        resize: function(photo, name) {
            var temp = '/tmp/w_' + name + '.png';
            return new promise(function(resolve, reject) {
                gm(photo).size(function(err, size) {
                    var that = this;
                    if (err) {
                        reject(err);
                    }
                    var smaller = size.width > size.height ? size.height : size.width;
                    var _size = smaller * 0.8;

                    request.get('https://s3.amazonaws.com/FOLDER/photos/watermark.png', function(e, r, body) {
                        gm(body)
                            .resize(_size)
                            .write(temp, function(error) {
                                if (error) reject(error);

                                that.composite(temp)
                                    .gravity('Center')
                                    .toBuffer(function(e, buffer) {
                                        if (e) reject(e);

                                        fs.access(temp, fs.F_OK, function(err) {
                                            if (!err) {
                                                fs.unlinkSync(temp);
                                            }
                                        });

                                        resolve(buffer);
                                    });
                            });
                    });
                });
            });
        }
    },
    resize: function(photo, width, height) {
        return new promise(function(resolve, reject) {
            gm(photo).resize(width, height).toBuffer(function(err, buffer) {
                if (err) {
                    reject(err);
                }

                resolve(buffer);
            });
        });
    },
    crop: function(photo, width, height) {
        return new promise(function(resolve, reject) {
            gm(photo).size(function(err, size) {
                if (err) {
                    reject(err);
                }

                var x = 0,
                    y = 0;
                if (size.width > size.height) {
                    this.resize(null, height);
                    x = (((height * size.width) / size.height) - width) / 2;
                } else {
                    this.resize(width);
                    y = (((width * size.height) / size.width) - height) / 2;
                }

                this.crop(width, height, x, y).toBuffer(function(err, buffer) {
                    resolve(buffer);
                });
            });
        });
    },
    process: function(type, photo, width, height) {
        if (type == 'thumb') {
            return service.crop(photo, width, height);
        } else {
            return service.resize(photo, width, height);
        }
    }
};


exports.handler = function(event, context, callback) {
    var $filename = event.filename,
        $session = event.session,
        $mimetype = null,
        $original = null,
        $watermarked = null;

    async.waterfall([
        function(_next) {
            service.s3.download(BUCKET, FOLDER + $session + '/original/' + $filename).then(function(_original) {
                $mimetype = _original.ContentType;
                $original = _original.Body;
                _next(null);
            }, function(_error) {
                _next(_error);
            });
        },
        function(_next) {
            service.watermark.resize($original, (Math.random().toString(36).slice(-6) + new Date().getTime())).then(function(_watermarked) {
                $watermarked = _watermarked;
                _next(null);
            });
        },
        function(_next) {
            async.each(SIZES, function(_image, _callback) {
                service.process(_image.type, _image.mark ? $watermarked : $original, _image.size, _image.size).then(function(_generated) {
                    service.s3.upload.async(_generated, BUCKET, FOLDER + $session + '/' + _image.type + '/' + (_image.type != 'card' ? _image.size + '_' : '') + $filename, $mimetype, _image.hide).then(function() {
                        _callback(null);
                    });
                });
            }, function() {
                _next(null);
            });
        }
    ], function() {
        callback(null, 'Imagens processadas. Session: ' + $session);
    });
};

2 个答案:

答案 0 :(得分:1)

旧程序需要很长时间才能完成,然后lambda会耗尽内存。

我解决了这个问题,在两个大小中打破了数组。然后使用async.each将函数复制到新数组。

这种新方法可以完美运行并创建所有图像。

答案 1 :(得分:0)

之前我遇到过这个错误,并最终追踪它以达到内存限制。幸运的是,我能够增加记忆的大小,这解决了问题。

不幸的是,我发现你已经处于最大允许内存并且仍然达到了极限。这些图片的上传量有多大?如果它们确实很大,并且您需要将输出作为一个图像,那么我可以看到如何做到的唯一方法就是上传巨大的图像文件,将其裁剪成x4或更小的图像,调整每个图像和然后再将每个人重新组合在一起。