如何在AWS Lambda上部署一个基于PhantomJS的Node应用?

4
我写了一个小型的Lambda函数,使用SpookyJS、CasperJS和PhantomJS工具链进行无头浏览,爬取网站。任务非常简单,几个月前它在Lambda上运行正常。最近我不得不对一些东西进行了更改,并希望再次工作在这个项目中,但是重新开始时,我发现Lambda在任何情况下都会出错。我的问题是如何在Lambda中运行phantomjs
我正在运行的示例代码是:
spooky.start('http://en.wikipedia.org/wiki/Spooky_the_Tuff_Little_Ghost');
spooky.then(function () {
    this.emit('hello', 'Hello, from ' + this.evaluate(function () {
        return document.title;
    }));
});
spooky.run();

我在Lambda中遇到的错误是:
{ [Error: Child terminated with non-zero exit code 1] details: { code: 1, signal: null } }

我已经尝试了多种方法以确保Lambda上的一切都能正常运行。下面是我尝试诊断的长列表:

  1. 本地使用node index.js运行并确认它能正常工作
  2. 按照npm安装调用建议的方式,将package.json和js文件上传到Amazon Linux EC2实例进行编译,详情请参见此处
  3. 在ec2实例上运行npm install,再次运行node index.js以确保输出正确
  4. 压缩所有内容,并使用cli部署到AWS

我的package.json文件如下:

{
  "name": "lambda-spooky-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "casperjs": "^1.1.3",
    "phantomjs-prebuilt": "^2.1.10",
    "spooky": "^0.2.5"
  }
}

我曾尝试以下方法(大多数在本地和AWS EC2实例上也有效),但在Lambda上出现了相同的错误:
  1. Trying the non -prebuilt version of phantom
  2. Ensuring casperjs and phantomjs are accessible from the path with process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'] + ':' + process.env['LAMBDA_TASK_ROOT'] + '/node_modules/.bin'; console.log( 'PATH: ' + process.env.PATH );
  3. Inspecting spawn calls by wrapping child_process's .spawn() call, and got the following:

    { '0': 'casperjs',
      '1': 
       [ '/var/task/node_modules/spooky/lib/bootstrap.js',
         '--transport=http',
         '--command=casperjs',
         '--port=8081',
         '--spooky_lib=/var/task/node_modules/spooky/lib/../',
         '--spawnOptions=[object Object]' ],
      '2': {} }
    
  4. Calling .exec('casperjs') and .exec('phantomjs --version') directly, confirming it works locally and on EC2, but gets the following error in Lambda. The command:

    `require('child_process').exec('casperjs', (error, stdout, stderr) => {
    if (error) { console.error('error: ' + error); }
       console.log('out: ' + stdout);
       console.log('err: ' + stderr);
    });
    

得到以下结果:

err: Error: Command failed: /bin/sh -c casperjs
module.js:327
    throw err;
    ^

Error: Cannot find module '/var/task/node_modules/lib/phantomjs'
    at Function.Module._resolveFilename (module.js:325:15)
    at Function.Module._load (module.js:276:25)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (/var/task/node_modules/.bin/phantomjs:16:15)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)

2016-08-07T15:36:37.349Z    b9a1b509-5cb4-11e6-ae82-256a0a2817b9    sout: 
2016-08-07T15:36:37.349Z    b9a1b509-5cb4-11e6-ae82-256a0a2817b9    serr: module.js:327
    throw err;
    ^

Error: Cannot find module '/var/task/node_modules/lib/phantomjs'
    at Function.Module._resolveFilename (module.js:325:15)
    at Function.Module._load (module.js:276:25)
    at Module.require (module.js:353:17)
    at require (internal/module.js:12:17)
    at Object.<anonymous> (/var/task/node_modules/.bin/phantomjs:16:15)
    at Module._compile (module.js:409:26)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)
1个回答

3

我发现问题在于在路径中包含node_modules/.bin,因为这些文件只是简单地指向每个库中的/bin文件夹,所以在本地和ec2机器上都可以工作。但是,如果这些文件内部的调用使用相对路径,则会出现问题。问题如下:

[ec2-user@ip-172-31-32-87 .bin]$ ls -lrt
total 0
lrwxrwxrwx 1 ec2-user ec2-user 35 Aug  7 00:52 phantomjs -> ../phantomjs-prebuilt/bin/phantomjs
lrwxrwxrwx 1 ec2-user ec2-user 24 Aug  7 00:52 casperjs -> ../casperjs/bin/casperjs

我解决了这个问题,通过在Lambda处理程序中将每个库的bin目录添加到lambda路径中:
process.env['PATH'] = process.env['PATH'] + ':' + process.env['LAMBDA_TASK_ROOT'] 
        + ':' + process.env['LAMBDA_TASK_ROOT'] + '/node_modules/phantomjs-prebuilt/bin'
        + ':' + process.env['LAMBDA_TASK_ROOT'] + '/node_modules/casperjs/bin';

现在Lambda可以正确地运行Phantom、Casper和Spooky。


如果有其他人发现了这个问题并遇到了类似的困境。即使在上述操作之后,我仍然遇到了“子进程以非零退出代码1终止”的问题。结果,我不得不进入node_modules下的casperjs目录并运行npm_update,因为它缺少依赖项,这些依赖项没有从父级正确引用。 - Nick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接