Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if Meteor.call() fails when server connection is down?

Tags:

meteor

When the Meteor server connection is lost, how can I verify that Meteor.call() failed? Meteor.call() doesn't return any value. Basically Ctrl+Z in the Meteor shell when your app is running, then do something in the app that triggers a Meteor.call i.e. adding a new blog post:

Meteor.call('createPhrase', phrase, function(error) {
  console.log("This NEVER gets called if server is down.");

  if (error) {
     throwError(error.reason);
  }
});

I tried using Session vars, but the reactivity screws it up, i.e. the code below will trigger an error in my template handler (that get's flashed to the browser quickly) and as soon as isMyError is set to true, then when the Meteor.call is successful the error goes away as per isMyError = false, but this looks really sloppy.

Session.set("isMyError", true);

Meteor.call('createPhrase', phrase, function(error) {
   console.log("This NEVER gets called if server is down.");

   Session.set("isMyError", false);

    if (error) {
        throwError(error.reason);
    }
});


Template.index.isMeteorStatus = function () {

   myClientStatus = Meteor.status();

   if ( (myClientStatus.connected === false) || (Session.get("isMyError") === true) ) {
     return false;
   } else {
     return true;
   }
};
like image 973
Giant Elk Avatar asked Jan 04 '14 21:01

Giant Elk


1 Answers

Meteor's calls are generally entered into a queue that are sent to the server in the order that they are called. If there is no connection they stay in the queue until the server is connected once more.

This is the reason nothing is returned because Meteor hopes that it can reconnect then send the call and when it does it does eventually return a result then.

If you want to validate whether the server is connected at the point of the call it's best to check Meteor.status().connected (which is reactive) and only run Meteor.call if it is else throw an error

if(Meteor.status().connected)
    Meteor.call(....
else throwError("Error - not connected");

You could also use navigator.onLine to check whether the network is connected.

The reason you would experience a 60 second delay with Meteor.status().connected on the true status of whether meteor is connected or not is there isn't really a way for a browser to check if its connected or not.

Meteor sends a periodic heartbeat, a 'h' on the websocket/long polling wire to check it is connected. Once it realizes it didn't get a heartbeat on the other end it marks the connection disconnected.

However, it also marks it as disconnected if a Meteor.call or some data is sent through and the socket isn't able to send any data. If you use a Meteor.call beforehand to Meteor.status().connected it would realize much sooner that it is disconnected. I'm not sure it would realize it immediately that you can use them one line after the next, but you could use a Meteor.setTimeout after a second or two to fire the call.

Attempt to succeed:

Meteor is designed very well to attempt to succeed. Instead of 'attempting to fail' with an error stating the network is not available its better to try and queue everything up until the connection is back.

The best thing to do would be to avoid telling the user the network is down because usually they would know this. The queued tasks ensure the userflow would be unchanged as soon as the connection is back.

So it would be better to work with the queues that are built into the reconnection process rather than to avoid them.

like image 70
Tarang Avatar answered Sep 16 '22 18:09

Tarang