2014-12-31 9 views
16

我来自java的背景,所以有点新手在JavaScript公约需要的Lambda。如何在lambda中构建连续的AWS服务调用,因为所有调用都是异步的?

我有这是为了做一个特定的顺序几个AWS的任务,根据先前的任务的结果lambda函数。

鉴于每个任务都异步报告其结果,我想知道是否正确的方法确保它们都以正确的顺序发生,并且一个操作的结果可用于调用下一个函数。

好像我有invoike在现有功能的回调每个功能,但似乎是将某种深度嵌套,不知道如果这是这样做的正确方式。

例如,对于这些函数,需要一个DynamoDB getItem,然后调用SNS来获取端点,然后进行SNS调用以发送消息,然后进行DynamoDB写入。

怎样做,在拉姆达的JavaScript以正确的方式,占所有异步?

+0

您是否找到解决方案? – Casper

回答

2

我不知道,但拉姆达你应该看看到节点async library,以此来排序异步函数。

异步使我的生活变得更加简单和我的代码更加有序,没有你在你的问题中提到的深度嵌套问题。

典型的异步代码可能看起来像:

async.waterfall([ 
    function doTheFirstThing(callback) { 
     db.somecollection.find({}).toArray(callback); 
    }, 
    function useresult(dbFindResult, callback) { 
     do some other stuff (could be synch or async) 
     etc etc etc 
     callback(null); 
], 
function (err) { 
    //this last function runs anytime any callback has an error, or if no error 
    // then when the last function in the array above invokes callback. 
    if (err) { sendForTheCodeDoctor(); } 
}); 

看一看在上面的链接异步DOCO。串行,并行,瀑布等有许多有用的功能。异步是积极维护,似乎非常可靠。

祝你好运!

-2

默认情况下,JavaScript是异步的。

所以,你必须做的一切,这不是使用这些库,你可以,但有简单的方法来解决这个问题。在这段代码中,我向电子邮件发送了来自事件的数据,但如果需要,您只需在函数内添加更多函数。

重要的是你的context.done();将会是,他将结束你的Lambda函数。你需要把他放在最后一个函数的末尾

var AWS = require('aws-sdk');  
AWS.config.credentials = { "accessKeyId": "AAAA","secretAccessKey": "BBBB"}; 
AWS.config.region = 'us-east-1'; 
var ses = new AWS.SES({apiVersion: '2010-12-01'}); 

exports.handler = function(event, context) { 

    console.log(event.nome); 
    console.log(event.email); 
    console.log(event.mensagem); 

    nome = event.nome; 
    email = event.email; 
    mensagem = event.mensagem; 

    var to = ['[email protected]']; 
    var from = '[email protected]'; 

    // Send email 
    mensagem = ""+nome+"||"+email+"||"+mensagem+""; 

    console.log(mensagem); 
    ses.sendEmail({ 
     Source: from, 
     Destination: { ToAddresses: to }, 
     Message: { 
      Subject: { 
       Data: 'Form contact our Site' 
      }, 
      Body: { 
       Text: { 
        Data: mensagem, 
       } 
      } 
     } 
    }, 
    function(err, data) { 
     if (err) { 
      console.log("ERROR="+err, err.stack); 
      context.done(); 
      } else { 
      console.log("EMAIL SENT="+data); 
      context.done(); 
      } 
    }); 
} 
4

我喜欢@jonathanbaraldi答案,但我认为,如果你管理与承诺控制流会更好。 Q库有一些便利功能,如nbind,它们可以帮助将节点样式的回调API(如aws-sdk)转换为promise。

因此,在本例中,我会发送一封电子邮件,然后一旦电子邮件回复回来,我会发送第二封电子邮件。这实际上是所要求的,按顺序调用多个服务。我使用承诺的then方法以垂直可读的方式管理它。还使用catch来处理错误。我认为它只是简单地嵌套回调函数读得更好。

var Q = require('q'); 
var AWS = require('aws-sdk');  
AWS.config.credentials = { "accessKeyId": "AAAA","secretAccessKey": "BBBB"}; 
AWS.config.region = 'us-east-1'; 

// Use a promised version of sendEmail 
var ses = new AWS.SES({apiVersion: '2010-12-01'}); 
var sendEmail = Q.nbind(ses.sendEmail, ses); 

exports.handler = function(event, context) { 

    console.log(event.nome); 
    console.log(event.email); 
    console.log(event.mensagem); 

    var nome = event.nome; 
    var email = event.email; 
    var mensagem = event.mensagem; 

    var to = ['[email protected]']; 
    var from = '[email protected]'; 

    // Send email 
    mensagem = ""+nome+"||"+email+"||"+mensagem+""; 

    console.log(mensagem); 

    var params = { 
     Source: from, 
     Destination: { ToAddresses: to }, 
     Message: { 
     Subject: { 
      Data: 'Form contact our Site' 
     }, 
     Body: { 
      Text: { 
       Data: mensagem, 
      } 
     } 
    }; 

    // Here is the white-meat of the program right here. 
    sendEmail(params) 
     .then(sendAnotherEmail) 
     .then(success) 
     .catch(logErrors); 

    function sendAnotherEmail(data) { 
     console.log("FIRST EMAIL SENT="+data); 

     // send a second one. 
     return sendEmail(params); 
    } 

    function logErrors(err) { 
     console.log("ERROR="+err, err.stack); 
     context.done(); 
    } 

    function success(data) { 
     console.log("SECOND EMAIL SENT="+data); 
     context.done(); 
    } 
} 
0

我想提供以下解决方案,它只是创建一个嵌套的函数结构。

// start with the last action 
var next = function() { context.succeed(); }; 

// for every new function, pass it the old one 
next = (function(param1, param2, next) { 
    return function() { serviceCall(param1, param2, next); }; 
})("x", "y", next); 

这样做是对所有的变量复制的函数中调用你想,那么它们的巢上一次调用内部。你会想要安排你的事件倒退。这实际上与制作回调金字塔一样,但是当您事先不知道函数调用的结构或数量时会起作用。您必须将函数封装在闭包中,以便复制正确的值。

通过这种方式,我可以对AWS服务调用进行排序,以使它们进入1-2-3并以关闭上下文结束。据推测,你也可以将它构造成一个堆栈而不是这个伪递归。

1

想到一个非常具体的解决方案是级联Lambda调用。例如,你可以写:

  1. 一个lambda函数从DynamoDB的东西,然后调用...
  2. ... lambda函数调用SNS得到一个端点,然后调用...
  3. ...一个lambda函数通过SNS发送一个消息,然后调用...
  4. ... lambda函数写入到DynamoDB

所有这些函数需要从先前的函数作为输入的输出。这当然是非常精细的,你可能决定对某些电话进行分组。这样做至少可以避免JS代码中的回调地狱。

(作为一个方面说明,我不知道DynamoDB如何很好地整合LAMBDA。AWS可能会发出针对然后可以通过拉姆达被处理的记录变更事件。)

0

刚看到这个古老的线程。请注意,JS的未来版本将改善这一点。看看ES2017 async/await语法,它将异步嵌套的回调混乱简化为类似代码的干净同步。 现在有一些polyfills可以基于ES2016语法为您提供此功能。

作为上一个FYI - AWS Lambda now supports .Net Core,它提供了这种干净的异步语法。