2015-06-09 6 views
14

Ich habe den folgenden Code für eine Lambda-Funktion:Querying DynamoDB mit Lambda tut nichts

console.log('Loading function'); 
var aws = require('aws-sdk'); 
var ddb = new aws.DynamoDB(); 

function getUser(userid) { 
    var q = ddb.getItem({ 
     TableName: "Users", 
     Key: { 
      userID: { S: userid } } 
     }, function(err, data) { 
      if (err) { 
       console.log(err); 
       return err; 
      } 
      else { 
       console.log(data); 
      } 
    }); 
    console.log(q); 
} 


exports.handler = function(event, context) { 
    console.log('Received event'); 
    getUser('user1'); 
    console.log("called DynamoDB"); 
    context.succeed(); 
}; 

Ich habe eine [Benutzer] Tabelle, die als solche definiert:

{ 
    "cognitoID": { "S": "token" }, 
    "email": { "S": "[email protected]" }, 
    "password": { "S": "somepassword" }, 
    "tos_aggreement": { "BOOL": true }, 
    "userID": { "S": "user1" } 
} 

als ich den Anruf Funktion (von der AWS-Konsole oder der CLI) Ich kann die Nachrichten in den Protokollen sehen, aber der Rückruf für die getItem() wird nie aufgerufen.

Ich habe versucht mit getItem (params) ohne Rückruf, dann die Rückrufe für vollständig, Erfolg und Misserfolg definiert, aber wenn ich die send(), wird auch die komplette Rückruf nicht aufgerufen.

Ich weiß, dass die Aufrufe asynchron sind und ich dachte, dass vielleicht die Lambda-Funktion beendet wurde, bevor die Abfrage durchgeführt wurde und daher der Callback nicht aufgerufen würde, aber ich fügte eine einfache dumme Schleife am Ende der Funktion und der Anruf endete nach 3 Sekunden, ohne dass die Rückrufe überhaupt angerufen wurden.

Ich habe versucht mit verschiedenen Funktionen BatchGetItem, GetItem, ListTables und Scan. Das Ergebnis ist das gleiche, kein Fehler, aber die Callback-Funktion wird nie aufgerufen.

Ich wette, wenn ich DynamoDB abfrage, ohne Lambda zu verwenden, wird es mir die Ergebnisse bringen, also frage ich mich wirklich, warum hier nichts passiert.

Ich erstelle eine Rolle für die Funktion und ich habe eine Richtlinie erstellt, die den Zugriff auf die Funktionalitäten in dynamoDB erlaubt, die ich brauche, aber ohne Erfolg.

Die Politik sieht wie folgt aus:

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
     { 
      "Effect": "Allow", 
      "Action": [ 
       "lambda:InvokeFunction" 
      ], 
      "Resource": "arn:aws:lambda:*:*:*" 
     }, 
     { 
      "Effect": "Allow", 
      "Action": [ 
       "dynamodb:GetItem", 
       "dynamodb:BatchGetItem", 
       "dynamodb:Scan", 
       "dynamodb:PutItem", 
       "dynamodb:Query", 
       "dynamodb:GetRecords", 
       "dynamodb:ListTables" 
      ], 
      "Resource": "arn:aws:dynamodb:*:*:*" 
     }, 
     { 
      "Action": [ 
       "logs:*" 
      ], 
      "Effect": "Allow", 
      "Resource": "*" 
     } 
    ] 
} 

ich die Politik im Simulator lief und es funktionierte, wie ich dachte, es würde. Vorschläge?

+0

Haben Sie eine Nachricht erhalten, die besagt, dass der Prozess beendet wurde, bevor die Anfrage abgeschlossen wurde? –

+0

Nein, weil ich dort einen context.done() - oder context.succeed() -Aufruf hatte. Das Problem ist, dass das JSNode-Skript asynchron ist und wenn Sie einen Aufruf von dynamoDB ausführen, werden seine Callbacks möglicherweise nie aufgerufen, da die Lambda-Funktion beendet wird. Tatsächlich hat die DynamoDB-Aktion nicht einmal Zeit, anzufangen. –

Antwort

13

So stellt sich heraus, dass der Code korrekt ist. Das Problem ist, dass die Dynamodb-API alle diese Rückrufe verwendet und die Funktion endet, BEVOR die Daten abgerufen wurden.

Die schnellste Lösung ist das Entfernen des context.succeed() Anrufs und die Daten werden abgerufen. Natürlich würde die Verwendung des asynchronen Moduls helfen, und wenn Sie das nicht verwenden möchten, fügen Sie einfach einen Zähler oder einen booleschen Wert zu Ihrem Callback hinzu und warten Sie dann, bis sich der Wert geändert hat, um anzuzeigen, dass der Callback aufgerufen wurde (welche Art von saugt, wenn Sie daran denken)

+6

Anstatt einen Zähler und eine Schleife für nichts hinzuzufügen, denke ich, dass es am besten ist, die 'context.succeed()' von der Callback-Funktion wie folgt aufzurufen: \t console.log (data); \t context.succeed (Daten); –

4

Ich hatte einige ähnliche Probleme und fand nicht viele hilfreiche Ressourcen. Hier ist, was ich getan habe. Wahrscheinlich kann uns jemand schlauer sagen, ob das bestest ist.

function getHighScores(callback) { 
    var params = { 
     TableName : 'sessions', 
     ScanFilter: {"score":{"AttributeValueList":[{"N":"0"}], "ComparisonOperator":"GT"}}, 
    }; 
    var dynamo = new AWS.DynamoDB(); 
    dynamo.scan(params, function(err, data) { 
     if (err) { 
      console.log (err) 
      callback(err); 
     } else { 
      callback(data.Items); 
      console.log(data.Items); 
     } 
    }); 
} 



getHighScores(function (data) { 
    console.log(data); 
    context.succeed(data); 
}); 

Zusammengefasst die Rücksende der Rückruf durch die Hauptfunktion der kleineren Funktion ermöglicht die Anwendung, bis die Vollendung des Dynamo fortzusetzen. Behalten Sie context.succeed in der sekundären Funktion bei oder setzen Sie andere Funktionen dort fort.

+0

So habe ich es gemacht. Wenn Sie daran denken, ist das Problem nicht DynamoDB oder Lambda, sondern die Tatsache, dass Lambda-Funktion NodeJS-Code sind, was bedeutet, dass alles asynchron ist und Sie daher Callbacks überall haben müssen. Manchmal ist es nicht sehr bequem, aber es ist nur eine Frage des Einwickelns um alles im asynchronen Modus zu codieren :) –

+0

Wow, ich bin wirklich froh, dass du das gepostet hast. Ich habe versucht, dies stundenlang zur Arbeit zu bringen. Ich habe nichts gesehen, was dem hier in der Dokumentation ähnelt, aber es funktioniert! – dudeman

0

Um die Callback-Hölle zu vermeiden, verwenden Sie Promises. Es gibt einige ziemlich gute Tutorials auf youtube von einem Typen namens funfunfunction.

2

Mein Problem ist, dass mein Lambda in einer VPC lief, um sich mit ElastiCache zu verbinden.Dies führt dazu, dass alle Abfragen an öffentliche Internetressourcen wie DynamoDB und API Gateway auf unbestimmte Zeit unterbrochen werden. Ich musste in meiner VPC ein NAT-Gateway einrichten, um auf DynamoDB zugreifen zu können.

+0

Diese Antwort hat mir sehr geholfen, aber ich habe ein anderes Lambda für die Verbindung zu ElasticCache erstellt, damit ich das NAT-Gateway nicht zu meiner VPC hinzufügen muss, dann ist nur das ElastiCache-Lambda in meiner VPC und ich rufe es von meinem Haupt-Lambda ab nicht in der VPC) – fpg1503