Security News
Combatting Alert Fatigue by Prioritizing Malicious Intent
In 2023, data breaches surged 78% from zero-day and supply chain attacks, but developers are still buried under alerts that are unable to prevent these threats.
Flow control for Node.js
Check the suggested way to use Flowa
with Express.js
.
Each flow
is a set of tasks
. It starts by a compound task
which is basically a task that groups a set of single tasks
. Single tasks are async functions that are executed and called by passing an object called context
to allow sharing data between tasks and a callback
function. Each compound task's sub tasks are executed by a runner
that can be a series
execution (default type) or a parallel
execution.
npm install --save flowa
At the first you need to define our flow.
var Flowa = require('flowa');
// Define the flow
var flowa = new Flowa({
// Runner type
type: 'series',
// Do task1
task1: task1,
// Do task2
task2: task2
});
Then we need to execute the flow.
// To be used to share data between the tasks
var context = {};
// Execute the tasks
flowa.run(context).then(function(result) {
console.log(result);
}).catch(function(error) {
console.error(error);
});
And don't forget to write the code for your tasks.
// Do task1
function task1(context, callback) {
context.task1 = 1;
console.log('Executing task 1');
setTimeout(callback, 500);
}
// Do task2
function task2(context, callback) {
context.task2 = 1;
console.log('Executing task 2');
setTimeout(callback, 500);
}
Just put the 3 blocks of code together in one script and they will run smoothly.
There are no limitations about mixing the runners types. Add type
to the compound tasks to specify the runner type. But remember, it is not a good idea to make things too complex.
var flowa = new Flowa({
// Runner type
type: 'series',
// Do task1
task1: task1,
// Do task2 and task3 in parallel
group1: {
// Runner type
type: 'parallel',
// Do task2
task2: task2,
// Do task3
task3: task3,
// Do task4 and task5 in parallel
group2: {
// Runner type
type: 'series',
// Do task4
task4: task4,
// Do task5
task5: task5
}
},
// Do task6
task6: task6
});
You can jump forward and backward between tasks that belong to the same parent task and the runner type is series by passing the name of the task as the second argument to the callback function that is passed to each task. You can jump into a compound task too.
function task1(context, callback) {
callback(null, 'task6');
}
Since we have the ability to jump backward and forward, we can implement a task to try something and another task to check the result to decide either to jump back to the previous task or continue.
function task1(context, callback) {
// We are just generating a random boolean value here
context.checkSomething = Math.random() >= 0.5;
callback();
}
/**
* Task
*
* @param {Object} context
* @param {Function} callback
*/
function task2(context, callback) {
if (context.checkSomething) {
return callback();
}
// Retry
callback(null, 'task1');
}
The thrown errors and the errors passed as a first argument to the callback function can be handled by attaching a .catch()
to the returend promise from run()
method.
// Using callbacks (Recommended)
function checkUser(context, callback) {
callback(new Error('User is not found'));
}
// Using the `throw` operator
function checkUser(context, callback) {
throw new Error('User is not found');
}
You can use the shorthand syntax for naming the tasks by their functions names.
var flowa = new Flowa({
// Runner type
type: 'series',
// Shorthand format for task1: task1
task1,
// Shorthand format for task2:task2
task2,
// Shorthand format for task3:task3
task3,
// Shorthand format for task4:task4
task4,
// Shorthand format for task5:task5
task5,
// Shorthand format for task6:task6
task6
});
You can use Flowa
to make more readable and maintainable express.js
services.
To initilize your web server and load your services.
Note: No need to change the code, just add more services at the line 16.
var express = require('express');
var Flowa = require('./index.js');
var app = express();
/**
* A mapping between services names and their handlers
* @type {Object}
*/
var handlers = {};
/**
* RESTful API services
* @type {Array}
*/
var services = [
{name: 'greeting.get', path: '/greeting/:name', method: 'get'}
];
/**
* Get a function to handle a specific service
*
* @param {String} name the name of the service
* @return {Function}
*/
function getServiceHandler(name) {
return function(req, res) {
var handler = handlers[name];
var context = {req: req, res: res};
handler.run(context).then(function() {
res.end();
}).catch(function(error) {
if (res.headersSent) {
return res.end();
}
res.status(500).send({
error: 'Something went wrong !'
});
console.error(error);
});
};
}
// Foreach service, define its route and attach a handler
services.forEach(function(route) {
handlers[route.name] = new Flowa(require('./' + route.name)),
app[route.method](route.path, getServiceHandler(route.name));
});
app.listen(3000, console.log.bind(null, 'listening ...'));
An example of a service.
/**
* Generate a greeting message
*
* @author Mohammad Fares <faressoft.com@gmail.com>
*/
var counter = 0;
/**
* Increment the greeting counter
*
* @param {Object} context
* @param {Function} callback
*/
function incrementGreetingCounter(context, callback) {
context.counterValue = ++counter;
callback();
}
/**
* Generate a greeting message
*
* @param {Object} context
* @param {Function} callback
*/
function generateGreetingMessage(context, callback) {
context.res.send({
message: 'Hello ' + context.req.params.name,
counter: context.counterValue
});
callback();
}
module.exports = {
// Runner type
type: 'series',
// Increment the greeting counter
incrementGreetingCounter: incrementGreetingCounter,
// Generate a greeting message
generateGreetingMessage: generateGreetingMessage
};
To watch how the tasks being executed in realtime, you can activate the debug logging via the debug
option.
flowa.run(context, {debug: true});
To create Flowa objects
Promise
Execute the flow
To create Flowa objects.
Param | Type | Description |
---|---|---|
flow | Object | A compound task |
name | String | A name for the flow (Optional) |
Promise
Execute the flow. The Flowa object can be defined once and executed as many as you need.
Returns: Promise
- resolve with the passed context object
Param | Type | Description |
---|---|---|
context | Object | A shared object between the tasks (Optional) (default: {}) |
options | Object | (Optional) |
ETIMEDOUT
) if the timeout is exeeded (type: Number
).ETIMEDOUT
) if the timeout is exeeded (type: Number
).Boolean
).This project is under the MIT license.
FAQs
Service level control flow for Node.js
The npm package flowa receives a total of 11 weekly downloads. As such, flowa popularity was classified as not popular.
We found that flowa demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
In 2023, data breaches surged 78% from zero-day and supply chain attacks, but developers are still buried under alerts that are unable to prevent these threats.
Security News
Solo open source maintainers face burnout and security challenges, with 60% unpaid and 60% considering quitting.
Security News
License exceptions modify the terms of open source licenses, impacting how software can be used, modified, and distributed. Developers should be aware of the legal implications of these exceptions.