Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js: Return from function not acting as expected

I'm very new to javascript/node.js and I'm having trouble with the following code. This is the handler for API an call. The 2nd code segment is just like the 1st, except there is an additional database lookup Merchant.findOne(...), and therefor the 'newTransaction.save()' function is nested one level deeper.

Both code segments return the 'output' variable value correctly. However, the second code segment does NOT also properly save the 'newTransaction' to the Mongo database.

I'm pretty sure the issue has to do with how/when the code returning from newTransaction.save(function (err, transaction){..} but I can't seem to get it straightened out.

I have been looking all over the internet trying to understand and fix this, with no success. Any help is appreciated...

Here is the older, simpler code that works as expected:

 handler : function(request, reply) {

        var output = {
            "success": true,
            "operations": [],
            "epoch": Date.now()
        };


        Terminal.findById(request.payload.deviceNumber, function (err, terminal) {
            if (err) {
                return reply(Boom.internal('Error looking up terminal.', err));
            }
            if (terminal) {

                ticket.quote("bitstamp", "USD", 1, function (err, exchangeRate) {
                    if (err) {
                        console.error(err);
                        return reply(Boom.internal('Error obtaining ticket quote.', err));
                    }

                  var newTransaction = new Transaction({
                        terminal: request.payload.deviceNumber,
                        merchant: terminal.merchant,
                        ccExchangeRate: exchangeRate.buy,
                        fiatAmtDue: request.payload.transactionValue,
                        ccAmtDue: ccAmtDueTruncated
                    });

                    newTransaction.save(function (err, transaction){
                        if (err) {
                            return reply(Boom.internal('Error creating new transaction.', err));
                        }

                        output.operations.push(
                            {
                                "control": "KeyPairGenControl",
                                "rand": cc.pseudoRandomBytes(32).toString('hex'),
                                "follow": {
                                    "url": "/pos/v1/AddressAndEncKey",
                                    "post": {
                                        "transactionId": transaction.transactionId
                                    }
                                }
                            }
                        );

                        return reply(output);

                    });

                });
            } else {
                return reply(Boom.internal('Error looking up terminal.', err));
            }
        });
    }

Here is the new code that does NOT save the newTransaction data into the Mongo DB.

handler : function(request, reply) {

        var output = {
            "success": true,
            "operations": [],
            "epoch": Date.now()
        };


        Terminal.findById(request.payload.deviceNumber, function (err, terminal) {
            if (err) {
                return reply(Boom.internal('Error looking up terminal.', err));
            }
            if (terminal) {

                Merchant.findOne({merchantId: terminal.merchant}, function(err, merchant) {
                    if (err) {
                        console.log('Cannot find merchant');
                        return reply(output);
                    }
                    var processor = merchant.backendPaymentProcessor.name;
                    var localCurrency = merchant.localFiatCurrency;
    //###################
                    ticket.quote(processor, localCurrency, 1, function (err, exchangeRate) {
                        if (err) {
                            console.error(err);
                            return reply(Boom.internal('Error obtaining ticket quote.', err));
                        }

                        var newTransaction = new Transaction({
                            terminal: request.payload.deviceNumber,
                            merchant: terminal.merchant,
                            ccExchangeRate: exchangeRate.buy,
                            fiatAmtDue: request.payload.transactionValue,
                            ccAmtDue: ccAmtDueTruncated
                        });

                        newTransaction.save(function (err, transaction){
                            if (err) {
                                return reply(Boom.internal('Error creating new transaction.', err));
                            }

                            output.operations.push(
                                {
                                    "control": "KeyPairGenControl",
                                    "rand": cc.pseudoRandomBytes(32).toString('hex'),
                                    "follow": {
                                        "url": "/pos/v1/AddressAndEncKey",
                                        "post": {
                                            "transactionId": transaction.transactionId
                                        }
                                    }
                                }
                            );

                            return reply(output);

                        });

                    //return reply(output);

                    });
    //###################
                });
            } else {
                return reply(Boom.internal('Error looking up terminal.', err));
            }
        });
    }
like image 872
gearhead Avatar asked Aug 16 '16 13:08

gearhead


People also ask

Why is return statement not working in JavaScript?

Since you are returning from the callback function of the forEach that's why it isn't working fine. Since you are calling getLable hence you have to write the return statement in the scope of getLable function. But your return statement is in the scope of inner callback function.

What does return[] do in JavaScript?

The return statement stops the execution of a function and returns a value from that function.

What happens when you return a function?

A return statement ends the execution of a function, and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can return a value to the calling function.

Does node fetch return a promise?

fetch() The global fetch() method starts the process of fetching a resource from the network, returning a promise which is fulfilled once the response is available. The promise resolves to the Response object representing the response to your request.


1 Answers

I did a diff of your 2 version:

enter image description here

Check 1

ticket.quote

  • Callback are identical for both version
  • processor, localCurrency are different

    1. Is exchangeRate pass into callback correct?

Check 2

newTransaction.save

  • newTransaction and callback for .save are setup identical

    1. Check(console.log()) the values used in setting up new Transaction({...})
    2. Check transaction object received by callback
    3. Check/debug the code of Transaction.save().

I don't think the issue is with the code you posted. Both version reached return reply(output); inside newTransaction.save's callback. Very likely issue is inside Transaction class or Transaction.save() logic.

One scenario I can think of is when a transaction failed:

  1. Transaction object is available (even for failed transaction)
  2. Transaction Class / Transaction.save() does not write to db because transaction failed
  3. Transaction.save() pass transaction object to callback, but NOT setting err, even when it should.
like image 55
John Siu Avatar answered Oct 19 '22 21:10

John Siu