0

In my project, I need to remotely check an API and I want to do it one time, if it returns something I don't want, it has to check another time but after 5 seconds delay, then 10, then 15 then 30 seconds. If after 30 seconds still not the response I expected from API, then I throw an error to the client, but if API answers with the expected response I want (at check #1 or #2 or #3 or #4) to return something to the client and stop the checks.

this is my method:

Meteor.methods({
    'verifyUserOwnership': function() {
        function checkCard() {
            return false; // for testing, simulating the bad answer from api
        }

        var checkOwnership = function(nbrTry, delay){
            if (checkCard()) {
              //I will do something if API responds with wwhat I want 
            } else {
                if(nbrTry < 3){
                    delay +=5000;
                    Meteor.setTimeout(function(){checkOwnership(nbrTry+1, delay);}, delay);
                } else {
                    throw new Meteor.Error('Card could not be found' );// has to be sent to client if after all the tries, API did respond with somwthing bad
                }
            }
        }
        checkOwnership(0, 0);
    }
});

But With this code I have this error :

I20160809-12:56:06.928(-4)? Exception in setTimeout callback: Error:      [Card could not be found]
I20160809-12:56:06.929(-4)?     at checkOwnership     (server/methods.js:74:17)
I20160809-12:56:06.929(-4)?     at server/methods.js:72:40
I20160809-12:56:06.929(-4)?     at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
I20160809-12:56:06.929(-4)?     at packages/meteor/timers.js:6:1
I20160809-12:56:06.930(-4)?     at runWithEnvironment (packages/meteor/dynamics_nodejs.js:110:1)

I think it's something about fiber and Meteor.bindEnvironment but I am not sure how to do it.

Thank you.

Kalman
  • 8,001
  • 1
  • 27
  • 45
NOaMTL
  • 193
  • 1
  • 4
  • 13
  • can you fix up your code? kind of confused what I'm looking at. Is `function checkOwnership()` part of your server side method code? – Mabeh Al-Zuq Yadeek Aug 09 '16 at 17:11
  • **checkOwnership()** is a function inside the method. This function will be ran 4 times and each time a delay is added, if at the fourth time the **checkCard()** function still returns false (in my exemple i force the false) i want the method itself to throw a Meteor.Error and if **checkCard()** returns true, i want the method to return "VALID" to the client (in the callback from meteor.call. – NOaMTL Aug 09 '16 at 17:40
  • See http://stackoverflow.com/a/25941287/2805154 for the likely answer to your question, especially if you are attempting to coordinate multiple async requests from a method. – Michel Floyd Aug 09 '16 at 21:42
  • @MichelFloyd Thank you for the answer, i did read the post and tries to understand everything, and the only thing remaining blurry is how you stop the iteration. lets say when server is resolving the task, i want to stop it when it future returns a certain value. How do I manage to do it ? Thank you. – NOaMTL Aug 09 '16 at 22:53
  • Because in my project, i need to remotely check an API and I want to do it one time, if it returns something I don't want, it has to check another time but after 5 seconds delay, then 10 seconds then 30 seconds. If after 30 seconds still not the response I expected from API, then I throw an error to the client, but if API answers with the expected response I want (at check #1 or #2 or #3 or #4)to return something to the client and stop the checks. – NOaMTL Aug 09 '16 at 22:59

1 Answers1

0

Use node fibers to stop/restrict recursive callbacks until they return a value. So you mimic blocking.

First in your meteor app dir install: meteor npm install --save fibers

then change your code like so:

if (Meteor.isServer) {
var Future = Npm.require('fibers/future');


Meteor.methods({
    'verifyUserOwnership': function() {
        var fut = new Future();
        function checkCard() {
            return false; // for testing, simulating the bad answer from api
        }

        var checkOwnership = function(nbrTry, delay){
            if (checkCard()) {
              //I will do something if API responds with wwhat I want 
            } else {
                if(nbrTry < 3){
                    delay +=5000;
                    nbrTry +=1;
                    console.log(nbrTry)
                    console.log("out")
                    Meteor.setTimeout(function(){
                        console.log("in")
                        checkOwnership(nbrTry, delay);
                        fut.return('done');
                        return 'done';
                    }, delay);
                } else {
                    console.log('err');
                    throw new Meteor.Error('Card could not be found' );// has to be sent to client if after all the tries, API did respond with somwthing bad
                }
            }
        }
        if (nbrTry = 0)
            console.log("call")
            checkOwnership(0,0);
    }
});
}

and notice that your code now has to run server side. Check logs server side!

This code does return the error: Error: Future resolved more than once

but the final error returned in the chain is what you want as per your conditions:[Card could not be found]

Also see this link

Community
  • 1
  • 1
yusha uzumo
  • 211
  • 1
  • 4
  • 15