Câu hỏi Làm thế nào để bạn cấu trúc các cuộc gọi dịch vụ AWS tuần tự trong lambda cho tất cả các cuộc gọi là không đồng bộ?


Tôi đến từ một nền tảng java vì vậy một chút của một newbie trên các công ước Javascript cần thiết cho Lambda.

Tôi đã có một chức năng lambda đó là có nghĩa là để làm một số nhiệm vụ AWS theo một thứ tự cụ thể, tùy thuộc vào kết quả của nhiệm vụ trước đó.

Cho rằng mỗi tác vụ báo cáo kết quả của nó một cách không đồng bộ, tôi tự hỏi nếu đúng cách đảm bảo tất cả chúng xảy ra đúng trình tự, và kết quả của một hoạt động có sẵn để gọi hàm tiếp theo.

Có vẻ như tôi phải lập hóa đơn cho mỗi hàm trong hàm gọi lại của hàm trước, nhưng có vẻ như một số kiểu lồng sâu và tự hỏi liệu đó có phải là cách thích hợp để làm điều này không.

Ví dụ về các hàm này yêu cầu một getoem DynamoDB, theo sau là một cuộc gọi tới SNS để có được một điểm cuối, tiếp theo là một cuộc gọi SNS để gửi một tin nhắn, tiếp theo là một ghi DynamoDB.

Cách đúng để làm điều đó trong javascript lambda, kế toán cho tất cả những asynchronicity là gì?


16
2017-12-31 05:36


gốc


Bạn đã tìm thấy một giải pháp? - Casper


Các câu trả lời:


Tôi thích câu trả lời từ @jonathanbaraldi nhưng tôi nghĩ nó sẽ tốt hơn nếu bạn quản lý luồng điều khiển bằng Promises. Thư viện Q có một số chức năng tiện lợi như nbind giúp chuyển đổi kiểu gọi lại của API kiểu như aws-sdk thành lời hứa.

Vì vậy, trong ví dụ này tôi sẽ gửi một email, và sau đó ngay sau khi phản hồi email trở lại, tôi sẽ gửi một email thứ hai. Đây là cơ bản những gì đã được yêu cầu, gọi nhiều dịch vụ theo thứ tự. Tôi đang sử dụng then phương pháp hứa hẹn sẽ quản lý điều đó theo cách có thể đọc được theo chiều dọc. Cũng sử dụng catch để xử lý lỗi. Tôi nghĩ rằng nó đọc tốt hơn nhiều chỉ đơn giản là làm tổ chức năng gọi lại.

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@company.com.br'];
    var from = 'site@company.com.br';

    // 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();
    }
}

4
2018-03-20 08:22





Tôi không biết Lambda nhưng bạn nên nhìn vào nút thư viện async như một cách để sắp xếp các hàm không đồng bộ.

async đã làm cho cuộc sống của tôi dễ dàng hơn nhiều và mã của tôi nhiều thứ tự hơn mà không có vấn đề làm tổ sâu bạn đã đề cập trong câu hỏi của bạn.

Mã async điển hình có thể trông giống như sau:

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(); }
});

Có một cái nhìn tại doco async tại liên kết ở trên. Có nhiều chức năng hữu ích cho nối tiếp, song song, thác nước và nhiều chức năng khác. Async được duy trì tích cực và có vẻ rất đáng tin cậy.

chúc may mắn!


2
2017-12-31 06:31





Một giải pháp rất cụ thể mà tôi nghĩ đến là xếp các cuộc gọi Lambda. Ví dụ, bạn có thể viết:

  1. Hàm Lambda lấy một thứ từ DynamoDB, sau đó gọi…
  2. … Một hàm Lambda gọi SNS để nhận điểm cuối, sau đó gọi…
  3. … Một hàm Lambda gửi tin nhắn thông qua SNS, sau đó gọi…
  4. … Một hàm Lambda viết cho DynamoDB

Tất cả các hàm đó lấy đầu ra từ hàm trước làm đầu vào. Đây là khóa học rất tốt, và bạn có thể quyết định nhóm các cuộc gọi nhất định. Làm theo cách này tránh được địa ngục gọi lại trong mã JS của bạn ít nhất.

(Là một lưu ý phụ, tôi không chắc DynamoDB tích hợp tốt như thế nào với Lambda. AWS có thể phát ra các sự kiện thay đổi cho các bản ghi mà sau đó có thể được xử lý thông qua Lambda.)


1
2017-10-06 07:42





Tôi tìm thấy bài viết này mà dường như có câu trả lời trong javascript bản địa.

Năm mẫu giúp bạn chế ngự javascript không đồng bộ.


0
2017-12-31 08:25



Liên kết đã chết khi tôi cố gắng, tìm thấy liên kết này có thể là một tấm gương của bài báo: sking7.github.io/articles/389411742.html - Tony


Tôi muốn cung cấp các giải pháp sau đây, mà chỉ đơn giản là tạo ra một cấu trúc hàm lồng nhau.

// 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);

Điều này có nghĩa là sao chép tất cả các biến cho lệnh gọi hàm bạn muốn thực hiện, sau đó lồng chúng vào bên trong cuộc gọi trước đó. Bạn sẽ muốn lên lịch sự kiện của mình về phía sau. Điều này thực sự giống như làm cho một kim tự tháp gọi lại, nhưng hoạt động khi bạn không biết trước cấu trúc hoặc số lượng các cuộc gọi hàm. Bạn phải bọc hàm trong một đóng để giá trị chính xác được sao chép.

Bằng cách này tôi có thể sắp xếp các cuộc gọi dịch vụ AWS như vậy mà họ đi 1-2-3 và kết thúc bằng việc đóng ngữ cảnh. Có lẽ bạn cũng có thể cấu trúc nó như là một chồng thay vì giả đệ quy này.


0
2017-09-16 21:30





Chỉ cần thấy chủ đề cũ này. Lưu ý rằng các phiên bản tương lai của JS sẽ cải thiện điều đó. Hãy nhìn vào ES2017 không đồng bộ / đang chờ cú pháp sắp xếp một mớ hỗn độn gọi lại async lồng nhau vào một đồng bộ hóa sạch sẽ như mã. Bây giờ có một số polyfills có thể cung cấp cho bạn chức năng này dựa trên cú pháp ES2016.

Như một FYI cuối cùng - AWS Lambda bây giờ hỗ trợ .Net Core cung cấp cú pháp không đồng bộ rõ ràng này ra khỏi hộp.


0
2018-01-24 20:31





Câu trả lời ngắn:

Sử dụng Async / Await - và gọi dịch vụ AWS (SNS chẳng hạn) với phần mở rộng .promise () để báo aws-sdk sử dụng phiên bản được hứa hẹn của chức năng dịch vụ thay vì phiên bản dựa trên cuộc gọi.

Vì bạn muốn thực hiện chúng theo một thứ tự cụ thể, bạn có thể sử dụng Async / Await giả định rằng hàm cha bạn đang gọi chúng từ chính nó là không đồng bộ.

Ví dụ:

let snsResult = await sns.publish({
    Message: snsPayload,
    MessageStructure: 'json',
    TargetArn: endPointArn
}, async function (err, data) {
    if (err) {
        console.log("SNS Push Failed:");
        console.log(err.stack);
        return;
    }
    console.log('SNS push suceeded: ' + data);
    return data;
}).promise();

Phần quan trọng là .promise () ở cuối đó. Tài liệu đầy đủ về việc sử dụng aws-sdk theo cách thức không đồng bộ / lời hứa có thể tìm thấy tại đây: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html

Để chạy một tác vụ aws-sdk khác, bạn sẽ thêm tương tự như chờ đợi và phần mở rộng .promise () vào hàm đó (giả định rằng có sẵn).

Đối với bất cứ ai chạy vào chủ đề này và thực sự tìm cách đơn giản đẩy lời hứa vào một mảng và đợi cho mảng WHOLE đó kết thúc (bất kể lời hứa nào thực hiện trước). Tôi đã kết thúc với một cái gì đó như thế này:

let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
    Message: snsPayload,
    MessageStructure: 'json',
    TargetArn: endPointArn
}, async function (err, data) {
    if (err) {
        console.log("Search Push Failed:");
        console.log(err.stack);
        return;
    }
    console.log('Search push suceeded: ' + data);
    return data;
}).promise();

snsPromises.push(snsResult)
await Promise.all(snsPromises)

Hy vọng rằng sẽ giúp một người ngẫu nhiên tình cờ về điều này thông qua google như tôi đã làm!


0
2017-07-12 20:35





Theo mặc định Javascript là không đồng bộ.

Vì vậy, tất cả mọi thứ mà bạn phải làm, nó không phải để sử dụng những thư viện, bạn có thể, nhưng có những cách đơn giản để giải quyết điều này. Trong mã này, tôi đã gửi email, với dữ liệu đến từ sự kiện, nhưng nếu bạn muốn, bạn chỉ cần thêm nhiều chức năng hơn bên trong các hàm.

Điều quan trọng là nơi mà context.done () của bạn; sẽ có, anh ta sẽ kết thúc hàm Lambda của bạn. Bạn cần phải đưa anh ta vào kết thúc chức năng cuối cùng.

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@company.com.br'];
    var from = 'site@company.com.br';

    // 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();
          }
     });
}

-2
2018-02-18 04:00