Search code examples
node.jsaws-lambdaes6-promisebluebird

How to chain promises returned from multiple files in nodejs


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.


Solution

  • 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
        })
    }