I'm trying to write a Lambda code where I try to make multiple entries into DynamoDB and if it fails, I put an error message into SQS. I'm trying to do this using Promises.
my DDB.js file
var AWS = require('aws-sdk');
exports.operation = function(ddbEvent) {
var dynamoDB = new AWS.DynamoDB();
var params = {};
var operation = ddbEvent.operation;
switch(operation) {
case 'insert':
case 'modify':
params["Item"] = ddbEvent.entry;
//Fill in params object from ddbEvent;
return dynamoDb.putItem(params, function(err, data) {
//Nothing to do just log
if(err) {
//log error msg
} else {
//log success
}
}).promise();
case 'delete':
//Do nothing operation
return Promise.resolve();
default:
console.warn("unsupported");
}
};
my SQS.js file:
var AWS = require('aws-sdk');
exports.sqsOperation = function(message) {
var sqs = new AWS.SQS({
});
var params = {
//Use message to form the body
};
return sqs.sendMessage(params, function(err, data) {
//Nothing to do just log like in DDB.js
}).promise();
};
my main.js file (Lambda invoked) :
var AWS = require('aws-sdk');
var SQS = require('SQS');
var DDB = require('DDB');
exports.replicate = function(event, context, callback) {
var ddbPromise = [];
var sqsPromise = [];
event.Records.forEach((entry) => {
let p = DDB.operation(entry);
ddbPromise.push(p);
p.then(function(data) {
//write to ddb succssfull;
}).catch(function (err) {
//ddb save failed, try writing to sqs.
let sqsP = SQS.sqsOperation(entry);
sqsPromise.push(sqsP);
sqsP.then(function (data) {
//push to sqs success
}).catch(function (err) {
//push to sqs failed
});
});
});
var ddb_promises_all = Promise.all(ddbPromise);
ddb_promises_all.then(function (data) {
//all entries saved in DDB
callback(null, "success");
}).catch(function (err) {
//Now repeat wait for all sqs promises. If any sqs push failed then
//use callback(new Error("error"));
});
}
As can be seen, there is a mix of promises and callback patterns. I came across a library called bluebird, which can help avoid this problem. Would that be a better way? Is there a better way of chaining these promises, as I feel that saving the states in an array seems a wrong way to do as well as forcing to return a promise from a callback pattern would be neater if bluebird is used.
For your case, I'll prefer to extract them in some methods like
exports.replicate = function(event, context) {
// if possible, use Promise for consistency
return new Promise((resolve, reject) => {
// I feel that using `map` is cleaner than `forEach`
const ddbOperationPromises = event.Records.map(entry => ddbOperation(entry));
return Promise.all(ddbOperationPromises)
.then(data => {
// success
resolve();
})
.catch(err => {
// catch error
})
});
}
function ddbOperation(entry) {
return DDB.operation(entry)
.then((data) => {
// success
})
.catch((err) => {
return sqsOperation(entry);
})
}
function sqsOperation(entry) {
return SQS.sqsOperation(entry)
.then((data) => {
// success
})
.catch((err) => {
// handling err
})
}