Best way to time-out a Meteor.method() call?


#1

Meteor allows my web app to run even if the server is not available. That’s a really cool feature. Yet I’m still struggling to manage set-up things right for all potential scenarios, especially how to deal with an internet connection that breaks down once in a while, e.g. in an Cordova application.

For instance, how can gracefully react on a Meteor.call() call to the server that takes too long? Let me explain my scenario a bit better: Let us assume my client really “needs” information from the server to proceed, i.e. the data can not be “simulated”. Yet, I do not want to have the user wait “forever” if the server connection breaks down.

So I thought the best thing would be to set a timeout in the client-side of the Meteor.method() and inform the caller if the server did not respond in a specific time window. As there is no way to return a value from from Meteor.method() if .isSimulation == true, I assume the best thing to do was to pass a callback method for this.

However, I have no means at all to stop the server-side call then, so it may happen that the server reconnects and will return the result of its server-side Meteor.method() call once it is ready. So I would have to implement another tricky thing to catch these (now unwanted) callbacks from the server-side, which is all together not very elegant.

Maybe I missed something and there is better ways to do that, so I would be happy to hear about that.

I am also wondering if there is any mechanism by which a client can tell if the server connection is up and running or broken down? Or even better, a kind of event that fires when connection state changes?


#2

Check out Server Connections.

I’m still thinking about the rest of your post :wink:


#3

Oh, cool, I forgot there was a reactive source called Meteor.status() shameonme Thanks for the reminder :slight_smile:


#4

I don’t know how valid this would be, but you could do something like this. Of course the timeout should check if the connection is online …

if(Meteor.isClient) {
 methodCalls = {};
 var callId = Meteor.uuid();
 Meteor.call('my_method', new Date().getTime(), callId , function(err, result){
  if(result.context.callId)
  {
    if(result.context.callId in methodCalls)
    {
      Meteor.clearTimeout(methodCalls[result.context.callId]);
    }
  }
 });
 // unfortunately the stub method is not allowed to Meteor.setTimeout
 methodCalls[callId] = Meteor.setTimeout(function(){
    console.log('method '+callId+' did not return in time');
  }, 1000);
}

Meteor.methods({
  my_method: function(countdown, callId) {
    var context = this;
    context.callId = callId;
    if(this.isSimulation)
    {
      //
      // this runs on the client
      //
      console.log("Simulation: Hello Client "+countdown);
    }
    else
    {
      //
      // this only runs on the server
      // create small delay before returning
      //
      for(var i=parseInt(countdown,10);i>0;i--) {
        i-=2500;
      }
      //
      // the return value will be in the result parameter of the async callback
      //
      return {result: "Hello from Server method "+countdown, context: context};
    }
  }
});

#5

Thanks for this, will try that.