Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 176 lines (124 sloc) 9.102 kb

Advanced autoflow

Example defining directly using AST

Defining flow directly using the AST. Additional DSL interfaces can be built by simply having them build the proper AST.

var autoflow = require('autoflow');

function load(res, cb) { setTimeout(cb, 100, null, res + '-loaded'); }
function prefix(prefstr, str, cb) { setTimeout(cb, 100, null, prefstr + str); }
function postfix(str, poststr, cb) { setTimeout(cb, 100, null, str + poststr); }
function upper(str) { return str.toUpperCase(); }

var fn = autoflow();
var errors = fn.setAndValidateAST({
  inParams: ['res', 'prefstr', 'poststr'],
  tasks: [
    { f: load,    a: ['res'],              out: ['lres'] },
    { f: upper,   a: ['lres'],             out: ['ulres'], type: 'ret'  },
    { f: prefix,  a: ['prefstr', 'ulres'], out: ['plres'] },
    { f: postfix, a: ['plres', 'poststr'], out: ['plresp'] }
  ],
  outTask: { a: ['plresp'] }
});
console.error('errors:', errors); // []

fn('foo', 'pre-', '-post', function cb(err, lres) {
  console.error('err:', err);  // null
  console.error('lres:', lres); // pre-FOO-LOADED-post
});

AST Definition

The abstract syntax tree or AST provided by autoflow represents the data necessary to define the flow. By abstracting this from the DSL, it allows new skins or interfaces to be developed without need to change the core engine.

The AST is normally created at parse time when the autoflow main function is called (or one of the alternate DSL's is called). This can be done a module load time such that after loading the autoflow defined flow function's AST is generated and ready to process eliminating parsing and validation overhead when it is invoked in the future. This has the added advantage that since validation has also been performed that additional syntax issues or incomplete flow defintion errors can be caught quickly.

After the flow function has been created, you can review the generated AST for a function by accessing the ast.

var autoflow = require('autoflow');
var fn = autoflow('my-flow-name', 'paramName1, paramName2, cb -> err, outParamName1, outParamName2',
  functionRefOrMethodStr, 'paramName1, cb -> err, outParamName2',  // async cb task
  functionRefOrMethodStr2, 'paramName2, paramName1 -> outParamName1'   // sync task
);

console.error(fn.ast); // output the generated AST

The AST contains the following pieces:

  var ast = {
    name: flowName,
    inParams: [],
    tasks: [],
    outTask: {},
    locals: {}
  };
  • name - string - represents the name of the flow or function that will be created. autoflow will use the name when generating events so you can monitor progress and performance and also when errors occur.
  • InParams - array of strings - the flow input parameter names (excluding the callback param)
  • tasks - array of task defintion objects - each containing:
    • f - function reference or method string - async or sync function to be used for this task
    • a - array of input parameter names (excluding the callback param)
    • out - array of output parameter names (excluding the err parame)
    • type - type of function determining how function is invoked and its output style - one of: ('cb', 'ret', 'promise', 'when')
    • name - string - unique name for each task provided or generated by autoflow
  • OutTask - task definition object specifying the flow's output style and parameters containing:
    • f - will contain reference to the callback function at runtime
    • a - parameters being passed as output from the flow
  • locals - object provided which contains additional values that will become part of the autoflow variable space like input parameters but can be defined in advance at flow definition. This can be used to provide functions and objects to autoflow enabling string based DSL's. The global variables are already built-in, but any locals that are needed would be specified here.

Plugins (optional requires which turn on additional functionality)

Additional functionality which is not enabled by default but available by requiring additional modules.

LogEvents - log autoflow progress to stderr

For convenience in debugging or in monitoring flow and performance, autoflow has a built-in plugin for easily logging progress to stderr which is loaded and activated calling the autoflow method logEvents. It can be specified to log globally for all autoflow functions or only for particular autoflow functions. You also may optionally listen to select events rather than all flow and task events.

var autoflow = require('autoflow');
autoflow.logEvents(); // turn on flow and task logging for all autoflow functions

// OR

autoflow.logEvents(myautoflowFn); // turn on flow and task  logging for a specific function, repeat as needed
autoflow.LogEvents(myautoflowFn).logEvents(myautoflowFn2);  // can also chain

// Both methods can also take an optional event wildcard to specify what you want to listen to

autoflow.logEvents('flow.*'); // turn on flow logging for all autoflow functions
autoflow.logEvents(myautoflowFn, 'task.*'); // turn on task logging for myautoflowFn

To turn off logging

autoflow.logEvents(false); // turn off logging

Available Events that can be logged:

  • flow.begin - flow execution has started (receives a flow env)
  • flow.complete - flow execution has successfully completed (receives a flow env)
  • flow.errored - flow execution has errored (receives a flow env)
  • task.begin - task has started (receives task)
  • task.complete - task has successfully complted (receives task)
  • task.errored - task has errored (receives task)

Automatic Promise Resolution for inputs

If you want to automatically resolve promises in autoflow without having to manually call when or then, autoflow provides a plugin which will detect the existence of a then method (indicating a promise) at runtime from any inputs to the flow and will internally create when tasks to resolve them before passing the values to other tasks. This built-in plugin is not loaded normally but is loaded by invoking the autoflow method resolvePromises. External plugins like autoflow-deferred and autoflow-q also enable this but also provide additional promise integration. See https://github.com/jeffbski/autoflow-deferred and https://github.com/jeffbski/autoflow-q

var autoflow = require('autoflow');
autoflow.resolvePromises();  // turn on automatic promise detection and resolution

Track tasks - enable task tracking

Instead of only logging events to stderr (like LogEvents), this built-in plugin fires events that can be directly monitored. The LogEvent plugin uses this internally to get access to the metrics.

Enable this like the other built-in plugins using the method trackTasks

var autoflow = require('autoflow');
autoflow.trackTasks();  // turn on flow and task tracking events

Available Events that can be consumed

  • ast.defined - ast was defined (receives the ast)
  • flow.begin - flow execution has started (receives a flow env)
  • flow.complete - flow execution has successfully completed (receives a flow env)
  • flow.errored - flow execution has errored (receives a flow env)
  • task.begin - task has started (receives task)
  • task.complete - task has successfully complted (receives task)
  • task.errored - task has errored (receives task)

EventCollector - simple event accumulator for debug use

When developing or debugging it is often useful to accumulate events and then interrogate them to verify operation, especially in testing.

To make this easier to accomplish, this plugin provides a simple event accumulator for development use. Note that this accumulator is designed for short term debug use, as it will continue to accumulate events and does not have any size restrictions, it should not be used in production since it will just continue to grow in size unless manually cleared.

var autoflow = require('autoflow');
var collector = autoflow.createEventCollector();

collector.capture(); // capture all flow and task events for all autoflow flows
collector.capture('flow.*'); // capture all flow events for all autoflow flows
collector.capture(flowFn, 'task.*'); // capture task events on a flow
collector.capture(flowFn, 'flow.*'); // add capture flow events on a flow

var events = collector.list();  // retrieve the list of events
collector.clear();  // clear the list of events;

External Plugins

  • https://github.com/jeffbski/autoflow-deferred - integrates jQuery style Deferred/Promises with autoflow, providing automatic promise resolution and optional usage for autoflow functions where by calling without a callback returns a promise.
  • https://github.com/jeffbski/autoflow-q - integrates Q-style Deferred/Promises with autoflow, providing automatic promise resolution and optional usage for autoflow functions where by calling without a callback returns a promise.
Something went wrong with that request. Please try again.