为啥 AWS Lambda 函数在回调函数执行之前完成?

Posted

技术标签:

【中文标题】为啥 AWS Lambda 函数在回调函数执行之前完成?【英文标题】:Why Does AWS Lambda function finishes before callback function is executed?为什么 AWS Lambda 函数在回调函数执行之前完成? 【发布时间】:2018-08-12 16:13:27 【问题描述】:

我正在开展一个项目,以从音频文件中获取脚本。音频文件的格式为 flac。我正在使用 AWS Lambda 并在 node.js 中编写了代码。此外,我正在使用 IBM Speech to text 服务并使用他们提供的基本示例代码,可以在 here 找到。问题是我的 lambda 函数在运行这些函数之前完成。

我正在从 s3 下载文件并将其存储在本地(工作正常)。之后,我试图将相同的文件传递给 IBM Speech to Text SDK,它应该将音频文件的脚本返回到本地存储

代码如下:

const downloadFile = function (url1, dest, cb) 
    const file = fs.createWriteStream(dest);
    https.get(url1, function (res) 
        //res.setEncoding('binary');
        res.pipe(file);
        file.on('finish', function () 
            const stats = fs.statSync(dest);
            const fileSizeInBytes = stats.size;
        //Convert the file size to megabytes (optional)
            const fileSizeInMegabytes = fileSizeInBytes / 1000000.0;
            console.log(fileSizeInMegabytes);
            file.close();
            RunIBMWatson(dest);
            callback(null,"Nice");
        );
    );
;
function RunIBMWatson(dest)
    console.log(dest);
    console.log("I am here");

    const recognizeStream = speech_to_text.createRecognizeStream(params);
    fs.createReadStream(dest).pipe(recognizeStream);
    recognizeStream.pipe(fs.createWriteStream('/tmp/transcription.txt'));
    recognizeStream.setEncoding('utf8');
    recognizeStream.on('results', function(event)  onEvent('Results:', event); );
    recognizeStream.on('data', function(event)  onEvent('Data:', event); );
    recognizeStream.on('error', function(event)  onEvent('Error:', event); );
    recognizeStream.on('close', function(event)  onEvent('Close:', event); );
    recognizeStream.on('speaker_labels', function(event)  onEvent('Speaker_Labels:', event); );

    function onEvent(name, event) 
      console.log("I am in onEvent");
      if (name === 'data')
        console.log(event);
      

这是我从 AWS Lambda 获得的函数日志:

2018-03-05 03:31:53.585 54.093469
2018-03-05 03:31:53.588 /tmp/sample.flac
2018-03-05 03:31:53.588 I am here

我是 AWS Lambda 和 Node.js 的初学者。所以如果有人能指出我犯的错误。

【问题讨论】:

【参考方案1】:

是的,RunIBMWatson 是一个异步函数,因为文件 IO,所以因为你没有等待该函数的结果返回 - 回调被执行,从而结束你的 lambda 的执行。

RunIBMWatson 的逻辑包装在 Promise 中,一旦获得所有数据并将其写入该脚本文件 - 解析函数。 MDN: Promises

const downloadFile = function (url1, dest, cb) 

  ...
  console.log(fileSizeInMegabytes);
  file.close();
  return RunIBMWatson(dest)
  .then(() =>  // return data from promise resolve can be back and accessible as params
    callback(null,"Nice");
  


function RunIBMWatson(dest)

  return new Promise((resolve, reject) => 

    const rStream = speech_to_text.createRecognizeStream(params);
    fs.createReadStream(dest).pipe(rStream);

    rStream.pipe(fs.createWriteStream('/tmp/transcription.txt'));
    rStream.setEncoding('utf8');
    rStream.on('results', function(event)  onEvent('Results:', event); );
    rStream.on('data', function(event)  onEvent('Data:', event); );
    rStream.on('error', function(event)  onEvent('Error:', event); );
    rStream.on('close', function(event)  onEvent('Close:', event); );
    rStream.on('speaker_labels', function(event)  onEvent('Speaker_Labels:', event); );

    function onEvent(name, event) 
      console.log("I am in onEvent");
      if (name === 'data') // the data 
        resolve(); // you can return data too here
      
    
  )

希望对你有帮助

【讨论】:

【参考方案2】:

问题是 javascript 事件循环是空的,所以 Lambda 认为它已经完成。你可以下载一个 npm 模块async/await 来帮助解决这个问题。 info here

默认情况下不包含asyncawait,但这并不意味着您不能自己添加它。只需在本地添加包(npm install asyncawait),然后在上传 Lambda 函数之前将 node_modules 文件夹包含在 ZIP 中。

如果您想单独处理开发依赖项(例如:测试、aws-sdk 以在本地执行您的函数等),您可以将它们添加到 package.json 中的 devDependencies 下。

【讨论】:

谢谢。这有帮助。将开始使用 async/await

以上是关于为啥 AWS Lambda 函数在回调函数执行之前完成?的主要内容,如果未能解决你的问题,请参考以下文章

AWS Lambda 在向 SQS 发送消息之前完成

如何在AWS Lambda函数中进行外部api调用

c ++:为啥执行回调但回调定义之前的函数没有?

使用 Node.js 从 AWS Lambda 函数连接到 MySql 数据库,没有连接回调

AWS lambda函数未终止线程

AWS Lambda Callback的函数签名