node-workflows
TypeScript icon, indicating that this package has built-in type declarations

1.3.3 • Public • Published

node-workflows

npm npm

Simple and fast implementation of action-driven workflows for Node.js written in TypeScript.

Donate

Install

npm install node-workflows --save

Usage

Import

var Workflows = require('node-workflows');

The TypeScript way:

import * as Workflows from 'node-workflows';

Examples

Workflows.start(function(ctx) {
    // ACTION #0
    console.log('Entering ACTION #0...');
 
    // will be available in
    // 'previousValue' property
    // of the next action
    ctx.nextValue = 'MK';
 
    // result of the workflow
    ctx.result = 23979;
}, function(ctx) {
    // ACTION #1
    console.log('Entering ACTION #1...');
 
    // run "async"
    return new Promise(function(resolve, reject) {
        try {
            // ctx.previousValue == 'MK'
            // ctx.result == 23979
 
            setTimeout(function() {
                // a value for the execution
                ctx.value = 19861222;
 
                resolve('TM');  // will be available in
                                // 'previousValue' property
                                // of the next action
            }, 5000);
        }
        catch (e) {
            reject(e);
        }
    });
}, {
    // ACTION #2
 
    // use an object
    // with an 'execute()' method
    // instead a function
    execute: function(ctx) {
        console.log('Entering ACTION #2...');
 
        // ctx.previousValue == 'TM'
        // ctx.result == 23979
 
        // ctx.value == 19861222 (at first time)
        // ctx.value == 1781 (at 2nd time)
 
        ctx.result = 5979;  // set a result value
                            // for the workflow
    }
}, function(ctx) {
    // ACTION #3
    console.log('Entering ACTION #3...');
 
    // ctx.previousValue == undefined
    // ctx.result == 5979
 
    if (1781 !== ctx.value) {
        // ctx.value == 19861222
 
        ctx.value = 1781;
 
        // mark 'ACTION #2'
        // as next action
        ctx.goto(2);
    }
}).then(function(result) {
    // finished with SUCCESS
 
    console.log('SUCCESS: ' + result);  // 5979
                                        // s. ctx.result
}).catch(function(err) {
    // finished with ERROR
 
    console.log('ERROR: ' + err);
});

Jump / skip

var workflow = Workflows.create(function(ctx) {
    // ACTION #0
 
    // skip one action ('ACTION #1')
    ctx.skip(1);  // alternate: ctx.skip()
}, function(ctx) {
    // ACTION #1
 
    // mark 'ACTION #0'
    // as next ...
    ctx.gotoFirst();
 
    // ... but directly skip
    // #0 to #2
    ctx.skipWhile = function(ctxToCheck) {
        return ctxToCheck.index < 3;
    };
}, function(ctx) {
    // ACTION #2
 
    if (!ctx.value) {
        ctx.value = true;
 
        ctx.repeat();
    }
    else {
        ctx.goto(1);  // goto 'ACTION #1'
    }
}, function(ctx) {
    // ACTION #3
 
    ctx.gotoLast();  // goto last action ('ACTION #6')
}, function(ctx) {
    // ACTION #4
 
    ctx.value = 'PZ';
 
    // if we would reach here
    // we could finish
    // the execution by calling...
    ctx.finish();
}, function(ctx) {
    // ACTION #5
 
    // if we would reach here
    // we could jump to a previous
    // action by calling...
    ctx.goBack();  // goto to 'ACTION #4'
    ctx.goBack(2);  // goto to 'ACTION #3'
}, function(ctx) {
    // ACTION #6
 
    // ctx.value == undefined (because we never reached 'ACTION #4')
});
 
workflow.on('action.before', function(ctx) {
    console.log('ACTION #' + ctx.index);
 
    ctx.result = ctx.index;
});
 
workflow.start().then(function(result) {
    // success
 
    // result == 6
}).catch(function(err) {
    // ERROR!!!
});

Logging

var workflow = Workflows.create(function(ctx) {
    // ACTION #0
 
    var tag = 'ACTION #1';
 
    ctx.emerg('system is unusable', tag);
    ctx.alert('an action must be taken immediately', tag);
    ctx.crit('critical conditions', tag);
    ctx.err('error conditions', tag);
    ctx.warn('warning conditions', tag);
    ctx.note('normal but significant condition', tag);
 
    // the following messages will NOT logged
    // by default
    // 
    // you can change the minimal log level
    // by setting the
    // 'logLevel' property of 'workflow'
    ctx.info('informational messages', tag);
    ctx.dbg('debug messages', tag);
    ctx.trace('output anything', tag);
});
 
// add loggers by function ...
workflow.addLogger(function(ctx) {
    // log level / category is stored in
    // ctx.category
 
    console.log('[' + ctx.tag + ' :: ' + ctx.time + '' + ctx.message);
});
// ... and by object
workflow.addLogger({
    log: function(ctx) {
        // your code
    }
});
 
workflow.start().then(function(result) {
    // success
}).catch(function(err) {
    // ERROR!!!
});

Share values

// create workflow WITHOUT starting it
var newWorkflow = Workflows.create(function(ctx) {
    // ACTION #0
 
    // ctx.value == 'PZ'  (s. below - newWorkflow.start())
 
    ctx.value = 'MK';
    ctx.nextValue = 23979;  // will be available in 'previousValue' property
                            // of 'ACTION #1'
                            // and 'nextValue' will be resetted there
}, function(ctx) {
    // ACTION #1
 
    // ctx.previousValue == 23979 (from 'ACTION #0')
    // ctx.value == 'MK'
 
    ctx.value = 'TM';
    ctx.nextValue = 5979;  // for 'ACTION #2'
}, function(ctx) {
    // ACTION #2
 
    // ctx.previousValue == 5979
    // ctx.value == 'TM'
}, function(ctx) {
    // ACTION #3
 
    // ctx.previousValue == undefined
    // ctx.value == 'TM'
});
 
 
// START
newWorkflow.start('PZ').then(function() {
    // success
}).catch(function(err) {
    // ERROR!!!
});

States

// WORKFLOW #1
Workflows.start(function(ctx) {
    // will be available for all
    // actions while the current execution
    ctx.globals['action0'] = 'MK';
 
    // is availabe ONLY FOR THIS ACTION
    // and is availabe while the execution
    // of the underlying workflow
    ctx.state = 23979;
 
    // will be available for all
    // actions of all workflows
    // and is stored permanent
    ctx.permanentGlobals['workflow1_action0'] = 'A global value';
}, function(ctx) {
    // ACTION #1
 
    // ctx.globals.action0 == 'MK';
    // ctx.state == undefined
 
    ctx.state = 5979;
 
    //TODO
});
 
// WORKFLOW #2
Workflows.start(function(ctx) {
    // ctx.permanentGlobals['workflow1_action0'] == 'A global value'
});

Events

var workflow = Workflows.create();
 
// workflow events ...
workflow.on('action.after', function(err, ctx) {
    // AFTER workflow action has been invoked
});
workflow.on('action.before', function(ctx) {
    // BEFORE workflow action is being invoked
});
workflow.on('action.new', function(action, newActionCount) {
    // new action added
});
workflow.on('action.skip', function(ctx) {
    // this action has been skipped
});
workflow.on('end', function(err, workflowExecutionCount, result, endTime, value, previousValue, previousIndex) {
    // workflow has ended
});
workflow.on('logger.new', function(action, newLoggerCount) {
    // new logger added
});
workflow.on('reset', function() {
    // whole workflow has been resetted
});
workflow.on('reset.actions', function(oldEntries) {
    // workflow actions have been resetted
});
workflow.on('reset.actionstates', function(oldStates) {
    // states of workflow actions have
    // been resetted
});
workflow.on('reset.loggers', function(oldLoggerActions) {
    // loggers have been resetted
});
workflow.on('reset.state', function(oldValue) {
    // state value of workflow has been resetted
});
workflow.on('start', function(workflowExecutionCount, initialValue, startTime) {
    // workflow is starting
});
 
// custom events for the execution
workflow.then(function(ctx) {
    // ACTION #0
 
    ctx.events.on('myWorkflowEvent_0', function(val1, val2, val3) {
        // will be invoked via 'ACTION #1'
 
        // v == "TM+MK"
        var v = val1 + val2 + val3;
    });
}).next(function(ctx) {  // <= alias for 'then()'
    // ACTION #1
 
    // invokes event in 'ACTION #0'
    ctx.events.emit('myWorkflowEvent_0',
                    'TM', '+', 'MK');
 
    ctx.events.once('myWorkflowEvent_1', function() {
        // will be invoked via 'ACTION #2'
        // BUT: only once!
    });
}).next(function(ctx) {
    // ACTION #2
 
    ctx.events.emit('myWorkflowEvent_1');  // invokes event in 'ACTION #1'
    ctx.events.emit('myWorkflowEvent_1');  // DOES NOT invoke event in 'ACTION #1'
                                           // because it has already been invoked
 
    // s. below
    ctx.globalEvents.emit('myGlobalEvent', 1234);
    ctx.globalEvents.emit('myGlobalEvent', 5678);  // not invoked
 
    ctx.workflowEvents.emit('myCustomWorkflowEvent', 'XyZ_1');
    ctx.workflowEvents.emit('myCustomWorkflowEvent', 'XyZ_2');
});
 
// a global event
Workflows.EVENTS.once('myGlobalEvent', function(val) {
    // val == 1234
});
 
// a custom workflow event
workflow.on('myCustomWorkflowEvent', function(val) {
    // [0] val == 'XyZ_1'
    // [1] val == 'XyZ_2'
});
 
// START
workflow.start().then(function() {
    // success
}).catch(function() {
    // ERROR
});

Other information

Workflows.start(function(ctx) {
    // ctx.count              => the total number of all actions of that workflow
    // ctx.current            => the context of the current executing action
    // ctx.executions         => the number of action executions
    // ctx.index              => zero based index of THAT ACTION
    // ctx.isBetween          => is between first AND last action or not
    // ctx.isFirst            => is FIRST action or not
    // ctx.isLast             => is LAST action or not
    // ctx.previousEndTime    => the end time of the PREVIOUS action
    // ctx.previousIndex      => zero based index of the PREVIOUS action
    // ctx.previousStartTime  => the start time of the PREVIOUS action
    // ctx.startTime          => the start time of the workflow
    // ctx.time               => the start time of that action
    // ctx.workflowExecutions => the number workflow executions
});

Documentation

The full API documentation can be found here.

Package Sidebar

Install

npm i node-workflows

Weekly Downloads

27

Version

1.3.3

License

MIT

Last publish

Collaborators

  • mkloubert