1

I am trying to achieve the following functionality:

  • execute call back
  • resolve promise
  • check output
  • if not correct execute again

I have 'mimicked' the scenario with a timer, this reruns a script that makes a call to backend database for some information:

 _runCheckScript: function(bStart, bPreScript){
                var oController = this;
                var scriptTimerdeferred = $.Deferred();
                var promise = scriptTimerdeferred.promise();

                if(typeof(bStart) === "undefined"){
                    bStart = true;
                }

                if(typeof(bPreScript) === "undefined"){
                    bPreScript = true;
                }

                // if the HANA DB is not stopped or started, i.e. it is still starting up or shutting down
                // check the status again every x number of seconds as per the function
                var msTime = 10000;

                if(!bPreScript){
                    this._pushTextIntoConsoleModel("output", {"text":"The instance will be 'pinged' every " + msTime/1000 + " seconds for 2 minutes to monitor for status changes. After this, the script will be terminated."});
                }

                if(bPreScript){
                    var timesRun = 0;
                    var commandTimer = setInterval( function () {
                        timesRun += 1;
                        if(timesRun === 12){
                            scriptTimerdeferred.reject();
                            clearInterval(commandTimer);
                        }
                        // send the deferred to the next function so it can be resolved when finished
                        oController._checkScript(scriptTimerdeferred, bStart, bPreScript);
                    }, msTime);
                }



                return $.Deferred(function() {
                    var dbcheckDeffered = this;

                    promise.done(function () {
                        dbcheckDeffered.resolve();
                        console.log('Check finished');
                            oController._pushTextIntoConsoleModel("output", {"text":"Check finished."});
                    });

                });

The script it calls, has it's own promise as it calls another function:

_checkScript: function(scriptTimerdeferred, bStart, bPreScript){
            var oProperties = this.getView().getModel("configModel");
            var oParams = oProperties.getProperty("/oConfig/oParams");

            var deferred = $.Deferred();
            var promise = deferred.promise();
            var sCompareStatus1 = "inProg";
            var sCompareStatus2 = this._returnHanaCompareStatus(bStart, bPreScript);
            var sCompareStatus3 = this._returnHanaCompareStatus3(bStart, bPreScript);


            var params = {//some params};


            // Send the command
            this._sendAWSCommand(params, deferred);

            // When command is sent
                promise.done(function (oController) {
                    console.log('back to db check script');

                    var oCommandOutputModel = oController.getView().getModel("commandOutput");
                    var sStatus = oCommandOutputModel.Status;


                    // check that it's not in the wrong status for a start/stop
                    // or if it's a pre script check -> pre script checks always resolve first time
                    if(sStatus !== sCompareStatus1 && sStatus !== sCompareStatus2  && sStatus !==sCompareStatus3|| bPreScript){
                        scriptTimerdeferred.resolve();
                    }

                });
        },

This works, however what it does is:

  • set a timer to call the first script every x seconds (as the data is currently changing - a server is coming online)
  • the script runs and calls another function to get some data from the DB
  • when the call for data is resolved (complete) it comes back to 'promise.done' on the checkScript and only resolves the timer promise if it meets certain criteria
  • all the while, the initial timer is resending the call as eventually the DB will come online and the status will change

I am wondering if there is a better way to do this as currently I could have, for example, 3 calls to the DB that go unresolved then all resolve at the same time. I would prefer to run a command, wait for it to resolve, check the output, if it is not right then run command again.

Thanks!

neeko
  • 1,930
  • 8
  • 44
  • 67
  • 1
    Avoid the [deferred antipattern](http://stackoverflow.com/q/23803743/1048572?What-is-the-promise-construction-antipattern-and-how-to-avoid-it)! When you already have the `promise`, use `then` on it instead of wrapping a `new $.Deferrred(…)` around it. – Bergi May 09 '17 at 21:19
  • 1
    Regarding "*`this._sendAWSCommand(params, deferred);`*" - never use deferreds as parameters! Instead, let the function create the promise and *return* it. – Bergi May 09 '17 at 21:20

1 Answers1

1

I think what you want to do can be achieved carefully reading what explained in these links:

Promise Retry Design Patterns

In javascript, a function which returns promise and retries the inner async process best practice

See this jsfiddle

var max = 5;

var p = Promise.reject();
for(var i=0; i<max; i++) {
    p = p.catch(attempt).then(test);
}
p = p.then(processResult).catch(errorHandler);

function attempt() {
    var rand = Math.random();
    if(rand < 0.8) {
        throw rand;
    } else {
        return rand;
    }
}
function test(val) {
    if(val < 0.9) {
        throw val;
    } else {
        return val;
    }
}
function processResult(res) {
    console.log(res);
}
function errorHandler(err) {
    console.error(err);
}

It retries a promise infinite times since the condition is not satisfied. Your condition is the point you said "check the output". If your check fails, retry the promise. # Be careful to hold a limit case, promises waste memory. If your api/service/server/callreceiver is off, and you don't set a threshold, you could create an infinite chain of promises NO STOP

Community
  • 1
  • 1
quirimmo
  • 9,800
  • 3
  • 30
  • 45