1

Using angular-sails the sailsjs backend is usually called this way:

this.doSomethingWithItem = function(itemID, callback){
        $sails.put('/item/doSomething', {itemID:itemID}).
        success(function (data, status, headers, config) {
            callback(data);
        }).
        error(function (data, status, headers, config){
            alert('Error!');
        });
    };

In the backend, most of the Sails (v0.11.0) Controller functions are rather simple. An example might look like such:

  doSomething: function(req, res) {
    var p = req.params.all();
    postgresClientPool.connect(function(err, client, done) {
      client.query("SELECT item_do_something_in_this_awesome_function($1) AS dbreturn", [p.itemID], function(err, result) {
      done();
      if(err) {
          res.status(500).json({success: false});
        }
      else {
          res.json(result.rows[0].dbreturn[0]);
       }
    });
  });
 }

Now for reasons we can't influence we're experiencing quite frequent but rather short connection losses (between Client/Browser and nodeJS/sails-Server). The task is now to handle them as smooth for the user as possible and avoid any further inconvenience.

So, if during an ongoing request the connection is interrupted, the logic has to be something like:

  • Check if the connection interruption happened before or after the request reached the server.
  • If it happened before: re-perform the request.
  • If it happened afterwards: tell the backend to re-send the result of the request.

Now, how to achieve that?

I don't know if registering a $sails.on('disconnect'... in each service function is the best idea. And anyway, I haven't figured out yet how the de-register them after the function finished executing.

cis
  • 1,259
  • 15
  • 48
  • You are using standard HTTP so option with auto-resend response by backend is impossible. I would suggest to use some interceptor in Angular app and if your request lost connection, try to send it again. Should not be too complicated. – Marek Urbanowicz Nov 21 '16 at 13:24

1 Answers1

2

First of all, I would recommend you to separate your business logic out of the controller.

You can check this other answer: sails.js access controller method from controller method

By doing so, you would be able to actually make the call again from the controller, without having to do much.

Also, we will use the async.retry and async.apply functions from the async module.

For example, imagine you move your code to a service in api/services/CustomerService.js ex:

module.exports = {
    get: function (customerId, done) {
        // postgresClientPool should be available in a param or globally?
        // I'd prefer assigning it to the sails object...
        // and use it like sails.postgresClientPool
        postgresClientPool.connect(function (err, client, release) {
          if (err) {
            release();
            done(err);
          }
          client.query("SELECT getCustomer($1) AS dbreturn", [customerId],
            function (err, result) {
              release();
              if (err) {
                done(err);
              } else {
                done(undefined, result.rows[0].dbreturn[0]);
              }
            });
        });
      }
    };

Then, in your controller, for example, api/controllers/Customer.js:

get: function (req, res) {
    var p = req.params.all();
    async.retry(3, async.apply(CustomerService.get, p.customerID), function (err, result) {
      if (err) {
        res.status(500).json({
          success: false
        });
      } else {
        res.json(result);
      }
    })
  }

You should require async in the top of your controller.

Community
  • 1
  • 1
Luis Lobo Borobia
  • 994
  • 11
  • 25
  • Thanks for those hints! However, I'm not quite sure your answer addresses my actual problem. If res.json doesn't reach the client (browser) because the connection's lost - will an async error kick in here and trigger a retry? I doubt it. – cis Nov 22 '16 at 07:13