Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PhantomJS on AWS Lambda Always Timeout

I'm try to create a task on AWS Lambda that create PDF file from PhantomJS then upload it AWS S3 later.

Now, I try to run it on Lambda but it's always Timeout.

My Lambda has 128mb of ram. The runtime is node.js 4.4.3.

This is the error I got from Lambda

"errorMessage": "2017-03-01T08:05:56.255Z dfd4cfe8-fe55-11e6-bf24-e7edf412e037 Task timed out after 10.00 seconds"

Also these are the log output

REPORT RequestId: dfd4cfe8-fe55-11e6-bf24-e7edf412e037  Duration: 10000.08 ms   Billed Duration: 10000 ms   Memory Size: 128 MB Max Memory Used: 29 MB


2017-03-01T08:05:56.255Z dfd4cfe8-fe55-11e6-bf24-e7edf412e037 Task timed out after 10.00 seconds

This is my code.

Index.js

var childProcess = require('child_process');
var path = require('path');

exports.handler = function(event, context, callback) {

     // Set the path as described here: https://aws.amazon.com/blogs/compute/running-executables-in-aws-lambda/
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'];

     // Set the path to the phantomjs binary
     var phantomPath = path.join(__dirname, 'phantomjs_linux-x86_64');

     // Arguments for the phantom script
    var processArgs = [
         path.join(__dirname, 'phantom-script.js'),
         event.url
    ];

    // Launc the child process
    childProcess.execFile(phantomPath, processArgs, function(error, stdout, stderr) {
        if (error) {
            context.fail(error);
            return;
        }
        if (stderr) {
            context.fail(error);
            return;
        }
        context.succeed(stdout);
    });
}

phantom-script.js

 var system = require('system');
 var args = system.args;

 // Example of how to get arguments passed from node script
 // args[0] would be this file's name: phantom-script.js

 const url = "https://google.com";

 system.stdout.write('hello from phantom!');

 console.log("task start, target url = " + url);

 console.time("execute time");
 phantom.create().then(function(ph) {
     console.time("create Page");
     ph.createPage().then(function(page) {
         console.timeEnd("create Page");
         console.time("open website");
         page.open(url).then(function(status) {
             console.timeEnd("open website");
             console.time("render as pdf");
             page.render('google.pdf').then(function() {
                 console.timeEnd("render as pdf");
                 console.log('Page Rendered');
                 ph.exit();

                 // send to s3
                 console.timeEnd("execute time");
             });
         });
     });
 });


 // Send some info node's childProcess' stdout
 system.stdout.write('hello from phantom!')

 phantom.exit();

I try to do my work following this answer but it's not working.

I didn't get any of log from my phantom-script.js like it is not trigger but my task always timeout.

like image 688
Natsathorn Avatar asked Oct 18 '22 16:10

Natsathorn


1 Answers

After I spend a lot of time on it. I found the package name Phantomjs-Prebuilt that you can install it via npm. you have to do npm install on amazon linux instance or docker amazon linux that has node version 4.x (lambda is using node version 4.3). Otherwise it will not work on lambda.

Then, I updated my code like this.

Index.js

var phantomjs = require('phantomjs-prebuilt')

exports.handler = function(event, context, callback) {
    var sourceUrl = "https://example.com"
    var program = phantomjs.exec('phantom-script.js', sourceUrl)
    program.stdout.pipe(process.stdout)
    program.stderr.pipe(process.stderr)
    program.on('exit', code => {
        // do something here after you phantomjs finish.
        return
    })
}

phantom-script.js

var system = require('system')
var args = system.args

// Example of how to get arguments passed from node script
// args[0] would be this file's name: phantom-script.js

var url = args[1] // received sourceUrl value

// Send some info node's childProcess' stdout
system.stdout.write('phantomJS running\r\n')

var webpage = require('webpage').create()

webpage.paperSize = {
    format: 'A4',
    orientation: 'landscape'
}

webpage.open(url, function(status) {
    system.stdout.write('start open page\r\n')
    webpage.render('/tmp/web.pdf', {
        format: 'pdf',
        quality: '100'
    })
    system.stdout.write('finish render page\r\n')
    phantom.exit()
})

On lambda the place you can write a file is /tmp folder that why i saved the file there.

I'm running this via lambda with 192mb of ram. It's work really fine. I can create a screenshot of webpage that has 500 images with this setting. The most important thing is make sure your lambda is able to connect internet.

FYI, I realize that when phantom-script.js (the file i wrote phantom script in.) has an error your lambda will freeze until it timeout. That's why I always got this response from lambda Task timed out after 10.00 seconds.

like image 87
Natsathorn Avatar answered Oct 20 '22 22:10

Natsathorn