【问题标题】:Capturing output from process spawned from NodeJS Lambda捕获从 NodeJS Lambda 生成的进程的输出
【发布时间】:2019-06-10 22:45:01
【问题描述】:

我正在尝试捕获从用 NodeJS 编写的 AWS Lambda 启动的外部程序的输出。下面的完整示例代码。任何测试事件都可以,因为它并没有真正使用。

exports.handler = async (event) => {
    console.log ("Entering lambda" + JSON.stringify(event))

    var spawn = require('child_process').spawnSync;

    child_process = spawn ('aws', [' --version'], {
        stdio: 'inherit',
        stderr: 'inherit',
        shell: true
    })

    console.log ("done");
    const response = {
        statusCode: 200,
        body: JSON.stringify('done'),
    };
    return response;
};

当我运行它时,我得到以下输出(为简洁起见,我删除了测试事件详细信息,因为它无关紧要)。

没有看到的是我预期的 aws --version 命令的结果(我正在使用它来测试 AWS CLI 的正确调用,但任何 Linux 命令都可以)。代码确实 同步执行,因为如果我将调用替换为child_process = spawn ('sleep', ['1'], {,lambda 的执行时间会增长到 1117.85 毫秒,因此会发生一秒睡眠。但是执行日志中没有捕获任何内容。

START RequestId: 0c1287e2-d2ee-4436-a577-bc8ec3608120 Version: $LATEST
2019-01-16T19:12:45.130Z    0c1287e2-d2ee-4436-a577-bc8ec3608120    Entering lambda {...}
2019-01-16T19:12:45.143Z    0c1287e2-d2ee-4436-a577-bc8ec3608120    done
END RequestId: 0c1287e2-d2ee-4436-a577-bc8ec3608120
REPORT RequestId: 0c1287e2-d2ee-4436-a577-bc8ec3608120  Duration: 13.29 ms  Billed Duration: 100 ms     Memory Size: 128 MB Max Memory Used: 20 MB  

我做错了吗?或者有没有其他方法可以捕获用 NodeJS 编写的 Lambda 的输出(状态码、stdio、stderr)?

【问题讨论】:

  • 如果你在 Lambda 之外运行它,它可以工作吗?
  • 您提到了一秒钟的睡眠,但您发布的代码示例中没有这样的事情。同样在代码中,您使用的是spawnSync 而不是异步版本spawn,但您提到“代码/does/ 同步执行”。那么你想使用哪一个?
  • @jarmod:是的,我在 Windows 上尝试使用生成的命令为 spawn ('date', ['/t'],我可以看到输出。
  • @MilanCermak:关于sleep,我的错,那行仍然引用了原始代码,我现在修好了。另外,我正在使用spawnSync,就像在发布的代码中一样。我只是确认代码已执行并且按预期同步执行,以排除它根本没有执行的情况。
  • 我不确定 awscli 在 Lambda 环境中是否可用。还可能值得一看 lambda 项目 (github.com/alestic/lambdash),它使用 child_process 和 exec 在 Lambda 中运行任意命令。

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


【解决方案1】:

这对我有用(node.js 8.10 运行时)


exports.handler = async (event) => {
    const spawnSync = require('child_process').spawnSync;
    const process = spawnSync('echo', ['hello', 'world'], {
        stdio: 'pipe',
        stderr: 'pipe'
    });
    console.log(process.status);
    console.log(process.stdout.toString());
};

当尝试使用aws 运行时,它会引发ENOENT 错误。换句话说,该命令不可用。正如@jarmod 的问题 cmets 中提到的,我也相信 awscli 在 Lambda 容器中不可用。

可用的是 SDK,因此您可以 require('aws-sdk'); 而不将其捆绑到您的 Lambda 部署包中。

【讨论】:

  • 虽然这对我使用 echo 有效,但另一个程序 (praat_barren) 会抱怨它没有像预期的那样从 CLI 运行。底线:这个答案会更好stackoverflow.com/a/31104898/1717535
【解决方案2】:

aws-cli 是一个 python 包,没有安装在 Lambda 环境中。
要验证我的说法,您可以在此处键入 shell 命令http://www.lambdashell.com/ 并检查执行环境中默认安装的内容或检查official documentation

您上面的代码没有返回任何输出,因为尝试执行aws 返回ENOENT,这意味着该文件不可用。

如果您想在您的 lambda 函数中运行 aws,您可以按照以下说明操作:Call aws-cli from AWS Lambda

然而我会质疑为什么你想这样做? AWS-SDK 包含在本地运行时环境中,您可以直接从您的代码中调用任何 AWS API,而无需生成进程并处理标准输入/标准输出。我强烈建议不要从您的代码中生成 aws cli,而是使用 SDK。

但是,如果您确实想从 Lambda 运行进程并捕获 stdout 和 stderr,我就是这样做的。

'use strict';

const childProcess = require('child_process');

/*
 * Handle the chile process and returns a Promise
 * that resoved when process finishes executing
 * 
 * The Promise resolves an  exit_code
 */ 
function handleProcess(process) {


    return new Promise((resolve, reject) => {
        process.stdout.on('data', (data) => {
            console.log(`stdout: ${data}`);
            console.log('stdout');
        });

        process.stderr.on('data', (data) => {
            console.log(`stderr: ${data}`);
        });

        process.on('close', (code) => {
            console.log(`child process exited with code ${code}`);
            if (code === 0) {
                resolve(code);
            } else {
                reject(code);
            }
        });
    });
}



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

    // console.log(JSON.stringify(process.env, null, 2));
    // console.log(JSON.stringify(event, null, 2));

    return handleProcess(childProcess.spawn('ls', ['--version']))

        .then((exit_code) => {

            console.log(`exit_code = ${exit_code}`)
            let response = {
                statusCode: (0 == exit_code) ? 200 : 500,
                body: exit_code
            };                
            callback(null, response);

        })

        .catch((error) => {
            console.error(error);
            let response = {
                statusCode: 500,
                body: error
            };
            callback(null, response);
        });

}

【讨论】:

  • 原因:一些 S3 函数(特别是我需要运行的那个,sync)在 Javascript SDK 中不可用(它没有在 docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html 的文档中列出)。调用它的唯一方法是调用 CLI SDK 中的aws s3 sync 命令。
  • 感谢 stackoverflow.com/questions/33513604/… 的引用,我会回到 Python 并使用 lambda 打包 aws-cli。
  • @wishihadabettername 为什么要将文件同步到临时环境?
  • 我在两个 S3 存储桶之间进行同步,而不是在临时环境中进行同步。这就是为什么我想使用 lambda 事实上,我只需要能够从 AWS 中的某个位置触发同步,我不需要 EC2 实例(是的,我只能使用 CLI 从外部安排同步,但更喜欢将整个解决方案包含在 AWS 中)。
  • 确实,sync 不是 S3 API,因此在 SDK 中不可用。这是 CLI 内置的便利
猜你喜欢
  • 1970-01-01
  • 2018-07-23
  • 1970-01-01
  • 2015-12-12
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
  • 2013-02-09
  • 1970-01-01
相关资源
最近更新 更多