2014-12-31 12 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,它提供了這種乾淨的異步語法。