How to handle asynchronous requests correctly?

Say I have some kind of game. I have a buyItem function as follows:

buyItem: function (req, res) {
    // query the users balance
    // deduct user balance
    // buy the item
}

If I spam along this route before deducting the user's balance (second request), the user's balance is still positive.

What I tried:

buyItem: function (req, res) {
    if(req.session.user.busy) return false;
    req.session.user.busy = true;
    // query the users balance
    // deduct user balance
    // buy the item
}

The task req.session.user.busywill be undefinedfor the first requests ~ 5. So this also does not work.

How do we deal with such situations? I use the Sails.JS framework if that matters.

+2
source share
2 answers

Update 2

Sails 1.0 now has full support for transactions through .getDatastore(). Example:

// Get a reference to the default datastore, and start a transaction.
await sails.getDatastore().transaction(async (db, proceed)=> {
  // Now that we have a connection instance in `db`, pass it to Waterline
  // methods using `.usingConnection()` to make them part of the transaction:
  await BankAccount.update({ balance: 5000 }).usingConnection(db);
  // If an error is thrown, the transaction will be rolled back.
  // Or, you can catch errors yourself and call `proceed(err)`.
  // To commit the transaction, call `proceed()`
  return proceed();
  // You can also return a result with `proceed(null, result)`.
});

Update

, , . , , , , , (.query(), .findOne() ..) . Waterline , , , (, pg mysql).

, transaction. ( ), , (, Postgres MySQL), .query() . :

buyItem: function(req, res) {
  try {
    // Start the transaction
    User.query("BEGIN", function(err) {
      if (err) {throw new Error(err);}
      // Find the user
      User.findOne(req.param("userId").exec(function(err, user) {
        if (err) {throw new Error(err);}
        // Update the user balance
        user.balance = user.balance - req.param("itemCost");
        // Save the user
        user.save(function(err) {
          if (err) {throw new Error(err);}
          // Commit the transaction
          User.query("COMMIT", function(err) {
            if (err) {throw new Error(err);}
            // Display the updated user
            res.json(user);
          });
        });
      });
    });
  } 
  // If there are any problems, roll back the transaction
  catch(e) {
    User.query("ROLLBACK", function(err) {
      // The rollback failed--Catastrophic error!
      if (err) {return res.serverError(err);}
      // Return the error that resulted in the rollback
      return res.serverError(e);
    });
  }
}
+13

. , . node , .

var inProgress = {};

function buyItem(req, res) {
    if (inProgress[req.session.user.id]) {
        // send error response
        return;
    }

    inProgress[req.session.user.id] = true;

    // or whatever the function is..
    req.session.user.subtractBalance(10.00, function(err, success) {
        delete inProgress[req.session.user.id];

        // send success response
    });
}
0

All Articles