2014-12-29 13 views
11

Tôi đang sử dụng AWS và sử dụng AWS SDK for JavaScript in Node.js. Tôi đang cố gắng xây dựng một hàm AWS Lambda và bên trong tôi muốn lấy danh sách tất cả các cá thể Amazon EC2 của mình, nhưng tôi dường như không thể làm cho nó hoạt động được. Bất cứ ai có thể phát hiện ra những gì tôi đang làm sai?Tôi có thể liệt kê tất cả các cá thể Amazon EC2 của mình bằng cách sử dụng Node.js trong AWS Lambda như thế nào?

Đây là mã chức năng Lambda của tôi:

var AWS = require('aws-sdk'); 
AWS.config.region = 'us-west-1'; 

exports.handler = function(event, context) { 
    console.log("\n\nLoading handler\n\n"); 
    var ec2 = new AWS.EC2(); 
    ec2.describeInstances(function(err, data) { 
     console.log("\nIn describe instances:\n"); 
     if (err) console.log(err, err.stack); // an error occurred 
     else  console.log("\n\n" + data + "\n\n"); // successful response 
    }); 
    context.done(null, 'Function Finished!'); 
}; 

Và đây là chính sách của tôi (? Tôi nghĩ đó là đúng)

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
    { 
     "Effect": "Allow", 
     "Action": [ 
     "logs:*" 
     ], 
     "Resource": "arn:aws:logs:*:*:*" 
    }, 
    { 
    "Effect": "Allow", 
    "Action": [ 
     "ec2:*" 
    ], 
    "Resource": "arn:aws:ec2:*" 
    }, 
    { 
     "Effect": "Allow", 
     "Action": [ 
     "s3:GetObject", 
     "s3:PutObject" 
     ], 
     "Resource": [ 
     "arn:aws:s3:::*" 
     ] 
    } 
    ] 
} 

Và nếu tôi làm một console.log vào 'EC2' Tôi get:

{ config: 
    { credentials: 
     { expired: false, 
     expireTime: null, 
     accessKeyId: 'XXXXXXXXXXXXXXXXXX', 
     sessionToken: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 
     envPrefix: 'AWS' }, 
    credentialProvider: { providers: [Object] }, 
    region: 'us-west-1', 
    logger: null, 
    apiVersions: {}, 
    apiVersion: null, 
    endpoint: 'ec2.us-west-1.amazonaws.com', 
    httpOptions: { timeout: 120000 }, 
    maxRetries: undefined, 
    maxRedirects: 10, 
    paramValidation: true, 
    sslEnabled: true, 
    s3ForcePathStyle: false, 
    s3BucketEndpoint: false, 
    computeChecksums: true, 
    convertResponseTypes: true, 
    dynamoDbCrc32: true, 
    systemClockOffset: 0, 
    signatureVersion: 'v4' }, 
    isGlobalEndpoint: false, 
    endpoint: 
    { protocol: 'https:', 
    host: 'ec2.us-west-1.amazonaws.com', 
    port: 443, 
    hostname: 'ec2.us-west-1.amazonaws.com', 
    pathname: '/', 
    path: '/', 
    href: 'https://ec2.us-west-1.amazonaws.com/' } } 

Trả lời

11

Nguyên nhân có thể nhất là bạn đang chấm dứt dứt khoát hàm Lambda của mình trước khi hoàn thành cuộc gọi đến EC2 D API escribeInstances.

Lý do là Lambda giả định mã của bạn đã hoàn thành việc thực thi ngay khi bạn gọi context.done(...). Và điều này đang xảy ra trước khi gọi cuộc gọi console.log(... data ...).

Thứ tự lạ này xảy ra do cách thức hoạt động của NodeJS và cách hoạt động của SDK AWS cho JavaScript. Trong NodeJS bạn không bao giờ nên chặn thực thi. Một cuộc gọi đến một webservice (chẳng hạn như EC2) sẽ chặn thực thi. Do đó, SDK AWS cho JavaScript (cũng như hầu hết các thư viện NodeJS) hoạt động bằng cách thực hiện cuộc gọi không đồng bộ.

Thông thường, khi bạn có một cuộc gọi không đồng bộ, bạn chuyển hàm gọi lại vào cuộc gọi đó. Khi kết quả đã sẵn sàng, NodeJS sẽ thực hiện chức năng gọi lại .

Trong mã của bạn, function(err, data) {...} là hàm gọi lại. Điều này không được thực hiện ngay lập tức, nhưng sẽ được lên lịch thực hiện khi NodeJS thấy rằng cuộc gọi ec2.describeInstances đã nhận được kết quả của nó.

Ngay sau khi bạn lịch việc thực hiện các cuộc gọi của bạn trở lại, bạn đang gọi context.done(...), mà nói với Lambda: Tôi đang thực hiện, bạn có thể giết tôi. Và nó vui vẻ tuân theo và làm gián đoạn chức năng của bạn, trước khi cuộc gọi DescribeInstances EC2 nhận được dữ liệu của nó và chuyển nó đến hàm gọi lại của bạn.

Cách giải quyết sự cố?

Câu trả lời phải rõ ràng bây giờ: chỉ cần di chuyển context.done(...) cuộc gọi của bạn vào bên callback chức năng của bạn, ngay sau nếu/block khác chứa console.log(...data...) gọi:

ec2.describeInstances(function(err, data) { 
    console.log("\nIn describe instances:\n"); 
    if (err) console.log(err, err.stack); // an error occurred 
    else  console.log("\n\n" + data + "\n\n"); // successful response 
    context.done(null, 'Function Finished!'); 
}); 
+0

Cảm ơn bạn @Bruno. Làm thế nào để bạn hoàn thành cùng một vòng lặp - như tạo 10 hàng đợi SQS, chèn 20 thông điệp [batch api tồn tại, bên cạnh đó], nếu tôi đặt context.done() bên trong vòng lặp, điều đó không có nghĩa là lặp lại sẽ dừng sau khi thực hiện đơn lẻ (1 sau đó thực hiện một phần) –

Các vấn đề liên quan