naxis is a runtime flow execution controller and tracer, it's a simple package with zero dependencies and full unit testing coverage.
- Memory, timespan and CPU code tracing
- Static and dynamic middleware context binding
- Parallel execution of middlewares
- Supports synchronous and asynchronous middlewares
- Flow execution control: ignore, stack up, abort and flush operations
- Painless to use and unobstrusive to your code
- Improves modularity
- Easily extensible
const { GenericFlow } = require('naxis');
const util = require('util');
const flow = new GenericFlow();
flow.use(function mySynchronousMiddleware () {
this.dynamicValue *= this.staticValue;
}).setStaticContext({
staticValue: 2
});
flow.use(async function myAsynchronousMiddleware () {
this.dynamicValue /= this.staticValue;
}).setStaticContext({
staticValue: 3
})
flow.run({
dynamicValue: 50
}).then(({flow}) => {
console.log(util.inspect(flow.tracer.getTracing(), false, null));
}).catch((error) => {
console.error(error)
});
-
Snippet
- getMiddleware returns the snippet's middleware
- isAsync returns a boolean indicating if the function is asynchronous
- setAsync sets the behavior of the function (asynchronous or not)
- getName returns the snippet's name
- setName sets the snippet's name
- getStaticContext returns the snippet's static context
- setStaticContext sets the snippet's static context
-
FlowDriver
- abort aborts a flow execution
- getAbortedHRTimestamp returns the abortion high resolution timestamp
- skip skips a number of next snippets
- getSkipCount returns the number of snippets to be skipped
- decrementSkipCount decrements the number of snippets to be skipped
- getDynamicContext returns the snippet's dynamic context
- setDynamicContext sets the snippet's dynamic context
- stackUp stacks up snippets to be executed in parallel
- isStacked returns a boolean indicating if a snippet was stacked up
- resetStack resets the stack of parallel snippets
- setFlushFunction sets a flush function
- flush executes the flush function
- ignore ingores snippets
- isIgnored returns a boolean indicating if the snippet was ignored
- removeIgnored removes snippets from ignored list
-
FlowTracer
- markMemoryUsage marks a key to trace memory usage
- calculateMemoryUsage calculates a key memory usage
- getCPUCoresAverage returns the CPU cores usage average
- markCPUUsage marks a key to trace CPU usage
- calculateCPUUsage calculates a key CPU usage
- markTimespan marks a key start timespan
- calculateTimespan calculates a key end timespan
- markTracing marks a key full tracing
- calculateTracing calculates a key full tracing
- getTracing returns the tracing
- RuntimeError
- GenericFlow
const { Snippet } = require('naxis');
const snippet = new Snippet(function myMiddleware () {
// Do your awesome stuff
});
Snippets encapsulates middlewares to represent their behavior. The argument passed to constructor is the middleware itself and must be a function not an arrow function. If you pass a named function, the Snippet class will use the function's name as the middleware's name. You can pass asynchronous functions (with the async
) keyword, the snippet will autodetect that the function is asynchronous.
const middleware = snippet.getMiddleware();
Returns the middleware function of the snippet.
const isAsync = snippet.isAsync();
Returns a boolean indicating if the middleware is asynchronous.
asynchronousSnippet.setAsync(true);
synchronousSnippet.setAsync(false);
Sets the asynchronous behavior of the middleware, this is useful when you're passing asynchronous middlewares to snippets but not with the async
keyword.
const name = snippet.getName();
Returns the snippet's name.
snippet.setName('myMiddleware');
Sets the snippet name, this is useful when you're using anonymous functions as middlewares.
const staticContext = snippet.getStaticContext();
Returns the snippet's static context. Contexts are objects that are bound to middlewares to be their context. The static context is the object that will be bound regardless of the function's call.
snippet.setStaticContext({
myKey: myValue
});
Sets the snippet's static context.
const { FlowDriver } = require('naxis');
const flowDriver = new FlowDriver({
myKey: myValue
});
FlowDriver is a class to guide the flow execution. The argument passed in the constructor is the dynamic context. When a snippet is called, the dynamic and static context are merged and bound as the middleware's context.
flowDriver.abort();
Aborts the flow execution, this call doesn't throw exceptions/errors.
const hrTimestamp = flowDriver.getAbortedHRTimestamp();
Returns a bigint with the high resolution realtime timestamp of the flow abortion.
flowDriver.skip(2);
Sets a number of snippets to skip next in the flow execution.
const skipCount = flowDriver.getSkipCount();
Returns the number of snippets to be skipped.
flowDriver.decrementSkipCount();
Decrements the number of snippets to be skipped.
const dynamicContext = flowDriver.getDynamicContext();
Returns the driver's dynamic context.
flowDriver.setDynamicContext({
myKey: myValue
});
Sets the dynamic context, it's an alternative to pass the dynamic context in the driver's constructor.
flowDriver.stackUp('mySnippet1', 'mySnippet2');
Stacks up the specified snippets. Stacked snippets are executed in parallel. The arguments of this function are the names of the snippets to be executed in parallel.
const isStacked = flowDriver.isStacked('mySnippet1');
Returns a boolean indicating if the snippet was stacked up.
flowDriver.resetStack('mySnippet2');
Resets the stack to execute in parallel. If you pass snippet's names as arguments to this function only those will be removed from the stack. Otherwise, if you don't pass any argument to this function all the snippets of the stack will be removed.
flowDriver.setFlushFunction(async function () {
// Flush stacked snippets
});
Sets the flush function. The flush function needs to flush the stack of parallel snippets. You usually don't want to set this function, because the GenericFlow class will set a properly function to handle this task.
flowDriver.flush().then().catch();
Flushes the stack of parallel snippets. If you don't call this function in your flow execution the GenericFlow class will execute all the stack at the end of the flow execution.
flowDriver.ignore('mySnippet1', 'mySnippet2');
Ignores the specified snippets in the flow execution.
const isIgnored = flowDriver.isIgnored('mySnippet1');
Returns a boolean indicating if the snippet will be ignored.
flowDriver.removeIgnored('mySnippet1', 'mySnippet2');
Removes specified snippets from the list of ignored snippets.
const { FlowTracer } = require('naxis');
const flowTracer = new FlowTracer({
timespans: true,
memory: true,
cpu: true
});
FlowTracer is a metric tracer of the flow execution. By default, all metrics are traced as demonstrated in the example above. The GenericFlow class will trace every snippet of the flow. You'll see a lot of mark and calculate methods in this class. mark methods will mark a key in a point of time to start the tracing. calculate methods will mark the end of tracing and calculate the delta from the start.
flowTracer.markMemoryUsage('myKey');
Marks a key to be memory usage traced.
flowTracer.calculateMemoryUsage('myKey');
Calculates a key memory usage tracing.
FlowTracer.getCPUCoresAverage();
Returns the CPU cores usage average, this function is used internally by the methods that trace CPU usage.
flowTracer.markCPUUsage('myKey');
Marks a key to be CPU usage traced.
flowTracer.calculateCPUUsage('myKey');
Calculates a key CPU usage tracing.
flowTracer.markTimespan('myKey');
Marks a high resolution (bigint) realtime start timespan.
flowTracer.calculateTimespan('myKey');
Calculates a high resolution (bigint) realtime end timespan and elapsed time.
flowTracer.markTracing('myKey');
Marks a key to be traced (CPU, memory and timespan).
flowTracer.calculateTracing('myKey');
Calculates a key tracing (CPU, memory and timespan).
const tracing = flowTracer.getTracing();
Returns all traced keys and their values.
const { RuntimeError } = require('naxis');
The RuntimeError is a class that extends the Error
class. Every snippet that throws an error, the error will be encapsulated by the RuntimeError and will be rethrown by the GenericFlow.run() method. Every RuntimeError has an about attribute that tells you more about the error in the flow execution.
const { GenericFlow } = require('naxis');
const flow = new GenericFlow();
GenericFlow is a class to represent and handle a snippets flow execution.
const asyncSnippet = flow.use(async function myMiddleware1 () {});
const syncSnippet = flow.use(function myMiddleware2 () {});
Adds a middleware to be executed in the flow. The returned value from this function will always be a snippet (instance of Snippet class) with your middleware encapsulated.
flow.run().then().catch();
Executes the flow. You can optionally pass a custom FlowTracer and/or FlowDriver instances to be used by the snippets:
flow.run(flowDriver, flowTracer).then().catch();
// Only flow driver
flow.run(flowDriver).then().catch();
// Only flow tracer
flow.run(null, flowTracer).then().catch();
If you don't pass instances of the FlowTracer and FlowDriver classes, those values will be used as the class constructors
flow.run({ myKeyForDynamicContext: myValue }, { cpu: false ).then().catch();
And you can pass arguments to your snippets:
flow.run(null, null, arg1, arg2).then().catch();
Note that the first argument of your middlewares will always be an object with the FlowTracer and FlowDriver and other arguments will be the arguments that you passed in the run method call.
function myMiddleware ({
flow: {
driver,
tracer
}
}, arg1, arg2) {
// With driver you can control the flow from your middlewares!
// And tracer allows you to do custom tracings!
driver.skip(2);
tracer.markTracing('myComplexCode');
// Do your complex thing here
tracer.calculateTracing('myComplexCode');
}
This project is licensed under the Apache-2.0 license.
Copyright © 2019 Victor França Lopes