• With almost almost all setup type of functions asking for a callback when done, such as connect(), Tasker is a helpful tool to fire off what ever (asynchronous) tasks that have to complete successfully before moving on or - on completion with error(s) - take other actions.

    It is related to contributions made by @Alex in conversation about Javascript Promises?
    and [EDIT] @JumJum in conversation about Async handling.

    Taskser's main built-in features are:

    • supports ok and err or callbacks
    • supports retries
    • keeps statistics about successes / failures and (re)tries
    • furnishes retries
    • provides task with single tasker callback
    • provides task with try count
    • provides statistics, to ok and err callbacks
    • provides means for easy, complete start over
    • allows application defined names for task callback and try count
    • tasks are invoked with setTimeout() to avoid calling stack fill-up on retries of 'synchronous' / chained tasks.
    • supports the next() concept with nesting / chaining

    Initially, I had even a fatter version supporting (optional) extended logging, names for Tasker instances, names for the tasks, additional statistics about start time, end time, execution/elapsed time, and task results with passing them to the ok and err callbacks.

    The fat version included also a part callback function invoked on successful or failed completion of each individual task to take additional action.

    Dropping tries information, logging, and passing these things to the callbacks makes this implementation even lighter.

    I'm using it as a module for simplifying synchronization of my setup tasks. Use is though not limited to just that. Anywhere in the app where a set of things have to happen before process flow can continue, a new Tasker can be instantiated. Taskers are fully reentrant and can be nested/cascaded/chained...

    Setup of tasks can be inline in the Tasker constructor as anonymous functions or upfront as globally or locally scoped variables.

    Skeletal task definition looks like this:
    *Note: trie is for reserved word try ;-)*

    var taskX = function(done,trie) {
      // do things...
      // on success (in success callback):
      done(true);
      // on error (in failure callback):
      done(false); // for no retries
      done(false,3) // with 2 retries - totally 3 tries
    }; 
    

    For the ok and err setup see next post with example of 5 tasks.

    Invocation of the Tasker looks like this:

    Tasker.new([task0Fnct,task1Fnct,task2Fnc­t,...],okFnct,errFnct,lg);
    

    *Tasker code (with some doc):

    // Tasker - kind of a 'Purposed' Promise
    
    // allows retries, resumes when all task are completed with
    // either ok or error function depending on the tasks results
    
    // Helpful for sequence agnostic setup of multiple interdependent 
    // 'things' that require resume callbacks, for example:
    
    // Setup of multiple communication devices, display, GPS, etc.
    // When all successfully setup and ready, the application code
    // as placed in/passed as the ok() function will resume.
    
    // Task is a function that gets passed a done function and a try cnt.
    // On successfull completion, task calls done with true (in callback).
    // On failure, it calls done with false and optional number of tries.
    // ok and err functions get number of successfully passed tasks (oks)
    // and arrays of statutes (sts, true/false), actual tries, and tasks.
    
    // Tasker is invoked with array of tasks, ok and err function (and
    // optional boolean for logging:
    
    // Tasker.new([t0Fnct,t1Fnct,t2Fnct,...],ok­Fnct,errFnct,lg);
    
    // Tasker can be made fatter/leaner by adding statistics about
    // start, end, and execution times / removing log, oks, and tries
    
    var Tasker = (function(){
      var T = function(tasks,ok,err,lg) {
        this.tasks = tasks; 
        this.ok = (ok) ? ok : function(){};
        this.err = (err) ? err : function(){};
        this.cnt = 0; this.sts = []; this.tries = []; this.lg = lg;
        tasks.forEach(function(t,id){ this._do(this,t,id,1); },this);
      };
      T.prototype._do = function(_this,t,id,n) {
        if (this.lg) console.log("Task "+id+" kickoff "+n);
        var done = function(ok,tries){ _this.done(ok,id,n,tries); };
        this.tries[id] = n; setTimeout(function(){ t(done,n); },1); 
      },
      T.prototype.done = function(ok,id,n,tries) {
        if (this.lg) console.log("Task "+id+" try "+n+" ok: "+ok);
        this.cnt++; if (!(this.sts[id] = ok) && tries && (tries > n)) { 
          this.cnt--; this._do(this,this.tasks[id],id,n + 1); }
        if (this.cnt === this.tasks.length) {
          var oks = this.sts.filter(function(o){ return o; }).length;
          var sts = this.sts, _tries = this.tries, _tasks = this.tasks;
          this.sts = null; this.tries = null; this.tasks = null;
          this[(oks == this.cnt) ? "ok" : "err"](oks,sts,tries,tasks); 
        }
      };
      return T;
    })();
    

    *EDIT* (at the time of version 1v94 (2017-08-29))

    Feel free to continue reading in this conversation about Tasker... it will make you just more appreciate what happened here:

    Version 1v86 (2016-07-05) introduced Promise and Promise has matured thru version 1v91 (2017-01-12). Promise makes life of synchronizing/sequencing of asynchronous tasks/callback of callbacks of callbacks of... much much easier... Promise is practically the only way out of callback-hell.

  • Tasker example with 5 taks 0..4, where task 1 and 3 fail (emulated) twice and once and succeed in 3rd and 2nd try, respectively.

    // Setup of 5 task: t0..t4
    
    var t0 = function(done) { // task0
      console.log("t0 started");
      setTimeout(function(){
        done(true);
      },5000);
    };
    
    var t1 = function(done,trie) {
      console.log("t1 started");
      setTimeout(function(){
        var ok = trie >= 3; // emulating failure on 1st & 2nd try
        console.log("t1 " + trie + " ok: " + ok);
        done(ok,3); // allow 3 tries
      },2000);
    };
    
    var t2 = function(done) {
      console.log("t2 started");
      setTimeout(function(){
        done(true);
      },15000);
    };
    var t3 = function(done,trie) {
      console.log("t3 started");
      var ok = trie >= 2;
      console.log("t1 " + trie + " ok: " + ok);
      setTimeout(function(){
        done(ok,2);
      },2500);
    };
    var t4 = function(done) {
      console.log("t4 started");
      setTimeout(function(){
        done(true);
      },12500);
    };
    
    // define ok function - application
    var ok = function(oks,sts,tries,tasks) {
      console.log("All " + oks + 
        " tasks successfully executed.");
    };
    
    // define err function
    var err = function(oks,sts,tries,tasks) {
        console.log("Only " + oks + " tasks of " + 
          sts.length + " successfully executed.");
    };
    
    
    // Execute the tasks 
    new Tasker([t0,t1,t2,t3,t4],ok,err,true);
    

    The console output reads as follows:

     1v71 Copyright 2014 G.Williams
    >echo(0);
    Task 0 kickoff 1
    Task 1 kickoff 1
    Task 2 kickoff 1
    Task 3 kickoff 1
    Task 4 kickoff 1
    =undefined
    t0 started
    t1 started
    t2 started
    t3 started
    t1 1 ok: false
    t4 started
    t1 1 ok: false
    Task 1 try 1 ok: false
    Task 1 kickoff 2
    t1 started
    Task 3 try 1 ok: false
    Task 3 kickoff 2
    t3 started
    t1 2 ok: true
    t1 2 ok: false
    Task 1 try 2 ok: false
    Task 1 kickoff 3
    t1 started
    Task 0 try 1 ok: true
    Task 3 try 2 ok: true
    t1 3 ok: true
    Task 1 try 3 ok: true
    Task 4 try 1 ok: true
    Task 2 try 1 ok: true
    All 5 tasks successfully executed.
    > 
    
  • There was another option for async handling
    BTW, @allObjects, you have a message ;-)

  • I've seen your conversation about Promise. For me it was missing the support of re-try options, that's why I went on my own - and I did not need (so far) the other stuff - which of course my solution is missing: the next or goto. Sequencing I can make after a sync point with (the first) 'parallels' and then venture into the next ones the same way as I did into the very first one. I used a pattern I got known to in 86 when working on TANDEM NonStop Systems(R) - now server division of HP - and worked on code generators to take advantage of fault tolerance and parallel execution. Tandem was not a hardware based fault tolerance - like [IBM S/88'(http://domino.research.ibm.com/tchjr/jou­rnalindex.nsf/600cc5649e2871db8525681500­60213c/cfc96f12d1fb70c385256bfa00685bd8!­OpenDocument) and many others were/are - but more so on a software fault tolerance that allowed sync points in the application and not only in the system software (or hardwired in hardware / on the board).

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Tasker - Task synchronizer - kind of a 'purposed' Promise

Posted by Avatar for allObjects @allObjects

Actions