javascript - Stop running processes after a Promise is rejected -


i'm using following code working ok, problem when error, want stops other promises. example if chi.getcommand(val1, val2), send reject , got exception catch, want cancel promises chss.exe , app.getstatus(12); how can achieve that?

  var start = promise.all([       chi.getcommand(val1, val2),       chi.findandupdatecustomer()     ]).spread(function (command, customer) {         return chss.exe(runnabledoc, command, customer)                  .delay(10)                  .then(function (val) {                    if (val) console.log(val);                    return app.getstatus(12);                  });     }).catch(function (err) {         // catch , handle errors , when come here want stops chain above     }); 

this code of command in short:

function getcommand(method, cmd) {   return new promise(function (resolve, reject) {     ...     child.stderr.on('data', function (data) {         console.log('stderr: here!' + data);         reject(data);     }); } 

the console log stderr: here! printed resolve called!

update1

the thing stops getstatus when put process.exit(1) kill process, want stop chain of function getcommand in case im arriving catch block,

  1. is there way?
  2. is bug in bluebird ? use "bluebird": "2.9.34"

function getcommand(method, cmd) { return new promise(function (resolve, reject) {

var spawn = require('child_process').spawn; var ls = spawn("cmdbug",["/c","npm install express --save"]);       ls.on('error', function (err) {         console.log(err);         reject(err);     }); 

the error got

{ [error: spawn cmdr enoent] code: 'enoent', errno: 'enoent', syscall: 'spawn cmdbug', path: 'cmdr', spawnargs: [ '/g', 'npm install express --save' ] } { [error: spawn cmdbug enoent] code: 'enoent', errno: 'enoent', syscall: 'spawn cmdbug', path: 'cmdr', spawnargs: [ '/g', 'npm install express --save' ] } child process failed code -4058

and still process of getstatus writing console.

the code use , not testing is:

the getcommand function throw error!

var start= function () {     return new promise.all([         childp.getchildprocesscommand(val1, val2),         childp.findandupdatecustomer()     ]).spread(function (cmd, updated) {             //execute child process             return promise.all([                 childp.getcommand('spawn', cmd),                 app.getstatus(51000,10,1);             ]).catch(function (err) {                 // catch , handle errors                 console.log("an error occur: " + err);                 return;             })         }).catch(function (err) {             // catch , handle errors             console.log("an error occur: " + err);             return;         }) }(); 

the code check status is:

// returns promise resolves when port open  checkportstatus: function(port, host){   return new promise((resolve, reject) => {     portscanner.checkportstatus(port, host, function(error, status) {       if(error)         reject(error);       else if(status === 'open')         resolve(status);       else         reject(new error('port not open'));     });   }); },  // api function getstatus: function(port, retriesleft) {    const time_between_checks = 1000;   const host = '127.0.0.1';   const retries = 20;   retriesleft = retriesleft === void 0 ? retries : retriesleft;    if(!port) throw new error('port required');   if(retriesleft === 0) promise.reject('timed out');    return new promise((resolve, reject) => {      // if rejects, added work.     this.checkportstatus(port, host).then(resolve, error => {      console.log("waiting port " + port + " attempt: " + retry);       settimeout(() => {          this.getstatus(port, retriesleft - 1).then(resolve, reject);        }, time_between_checks);     });   }); } 

and see error in console , still see console log of following 10 attempts. console.log("waiting port " + port + " attempt: " + retry);

update2 when trying change @artur suggest in second option got error in recoursive call error is:

typeerror: cannot read property 'then' of undefined

this i've tried:

getstatus: function(port, retriesleft) {    const time_between_checks = 1000;   const host = '127.0.0.1';   const retries = 20;   retriesleft = retriesleft === void 0 ? retries : retriesleft;    if(!port) throw new error('port required');   if(retriesleft === 0) promise.reject('timed out');    var promise = new promise((resolve, reject) => {      // if rejects, added work.     this.checkportstatus(port, host).then(resolve, error => {      console.log("waiting port " + port + " attempt: " + retry);       settimeout(() => {         //the error in following recursive call         this.getstatus(port, retriesleft - 1).then(resolve, reject);        }, time_between_checks);       }).catch(function (error) {          return reject(error);      });         return {             promise:promise,     cancel: function() {         console.log('cancelling');         cleartimeout(token);         }         }     });   }); } 

as @esailija pointed out bluebird has cancellation mechanism built-in - nice , sure totally fine simple async computations.

promise.config({    cancellation: true  });    function createcancellablemock(result, time) {      return new promise(function(resolve, reject, oncancel) {        // var child = runcommand();      var token = settimeout(function() {        if (result) {          console.log('almost done', result);          resolve(result);        } else {          reject('_err_');        }      }, time);        oncancel(function() {        console.log('cancelling');        // child.kill('sigterm');        cleartimeout(token);      })    })    }    var op1 = createcancellablemock('ok-1', 1000);  //var op2 = createcancellablemock('ok-2', 500);  var op2 = createcancellablemock(null, 500); // rejected    promise.all([op1, op2])    .spread(function(v1, v2) {      console.log('both-ok', v1, v2)    })    .catch(function() {      console.error('error');      op1.cancel();    })    .finally(function() {      console.log('finally');    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.0/bluebird.core.js"></script>

update

you can cancel recursively defined actions (such retries). best strategy in such case not mangle action recursive behavior. in below snippet created simple wrapper illustrates point.

var too_many_retries_error = 'too_many_retries_error';  var prob_of_fail = 0.8;  var interval = 200;  var retries = 5;    var cancel_after = null;  //var cancel_after = interval * (retries/2);    promise.config({    cancellation: true  });    function retrywithcancel(params) {      // params = {op - operation retry (it should return promise, either ),    // interval - between retries, retries - number of retries }      console.log('running, retries left ', params.retries);      params = object.assign({}, params); // copy params - no side-effects please    params.retries--;    if (params.retries <= 0) {      console.error('too many retries');      return promise.reject(new error(too_many_retries_error));    }      return new promise(function(resolve, reject, oncancel) {        var o = params.op()        .catch(function() {          return promise.delay(params.interval)            .then(retrywithcancel.bind(null, params))            .catch(reject)        })        .then(resolve)          oncancel(function() {        console.log('cancelling, retries left: ', params.retries);        o.cancel();      });      })    }    function fakeoperation() {      return promise.delay(100)      .then(function() {        if (math.random() > prob_of_fail) {          return promise.resolve('success');        } else {          return promise.reject(new error('error'));        }        })  }    var p = retrywithcancel({      op: fakeoperation,      interval: interval,      retries: retries    })    .then(console.log.bind(console))    .catch(console.error.bind(console))    .finally(console.log.bind(console, 'done'))    if (cancel_after) {    settimeout(function() {      p.cancel();    }, cancel_after)  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.1/bluebird.js"></script>

original answer

in general promises great not offer cancellation mechanism out of box. pretty problematic in scenarios (e.g. https://github.com/whatwg/fetch/issues/27) , in case option cancel pretty handy well. valid option add yourself.

basic promise based solution

i distilled problem bare minimum , made browser runnable. downside of below approach after cancellation promise never resolve nor reject - in general case surely unacceptable. alternatively .cancel may reject promise special symbol. neither of these approaches seem elegant.

function createcancellablemock(result, time) {            // child = null;      var token = null ;      var p = new promise(function(resolve, reject) {                    // child = runcommand();          token = settimeout(function() {              if (result) {                  console.log('almost done', result);                  resolve(result);              }               else {                  reject('_err_');              }          }, time);      }      )            return {          promise: p,          cancel: function() {              console.log('cancelling');              // child.kill('sigterm');              cleartimeout(token);          }      }  }    var op1 = createcancellablemock('ok-1', 1000);  // var op2 = createcancellablemock('ok-2', 500);  var op2 = createcancellablemock(null, 500); // rejected    promise.all([op1.promise, op2.promise])  .then(function(vs) { // no spread in native implemantation      console.log('both-ok', vs[0], vs[1])  })  .catch(function() {      console.error('error');      op1.cancel();  })

observable based solution

for basic sequence of operations promises fine, there way more superior approach available: namely observables. not offer built-in cancellation / disposing mechanism, allow deal multiple values emitted , keep sophisticated async execution under strict control.

  function createcancellablemock(result, time) {        return rx.observable.create(function(observer) {          var done = false;        var token = settimeout(function() {          if (result) {            console.log('almost done: ' + result);            observer.onnext(result);            observer.oncompleted();          } else {            observer.onerror('_err_');          }        }, time);          // called upon `disposed`        return function() {          console.log('disposing, done: ', done);          if (!done) {            cleartimeout(token);          }        }        })      }      var op1 = createcancellablemock('ok-1', 1000);    //var op2 = createcancellablemock('ok-2', 500);    var op2 = createcancellablemock(null, 500); // rejected      op1.zip(op2)      .catch(function(err) {        // disposed automatically :) hurray        console.log('caught', err);        // return rx.observable.empty(); // swallowing        return rx.observable.throw(err); // throwing        })      .subscribe(function(vs) {          console.log('both-ok', vs[0], vs[1])        },        function(err) {          console.error('unhandled error', err);        },        function() {          console.log('upon successful termination.')        }      );
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.0.7/rx.all.js"></script>


Comments

Popular posts from this blog

java - pagination of xlsx file to XSSFworkbook using apache POI -

Unlimited choices in BASH case statement -

apache - How do I stop my index.php being run twice for every user -