naxis v1.0.1
naxis
naxis is a runtime flow execution controller and tracer, it's a simple package with zero dependencies and full unit testing coverage.
Features:
- 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
Example
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)
});
API Reference
- 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
Snippet
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.
getMiddleware
const middleware = snippet.getMiddleware();
Returns the middleware function of the snippet.
isAsync
const isAsync = snippet.isAsync();
Returns a boolean indicating if the middleware is asynchronous.
setAsync
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.
getName
const name = snippet.getName();
Returns the snippet's name.
setName
snippet.setName('myMiddleware');
Sets the snippet name, this is useful when you're using anonymous functions as middlewares.
getStaticContext
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.
setStaticContext
snippet.setStaticContext({
myKey: myValue
});
Sets the snippet's static context.
FlowDriver
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.
abort
flowDriver.abort();
Aborts the flow execution, this call doesn't throw exceptions/errors.
getAbortedHRTimestamp
const hrTimestamp = flowDriver.getAbortedHRTimestamp();
Returns a bigint with the high resolution realtime timestamp of the flow abortion.
skip
flowDriver.skip(2);
Sets a number of snippets to skip next in the flow execution.
getSkipCount
const skipCount = flowDriver.getSkipCount();
Returns the number of snippets to be skipped.
decrementSkipCount
flowDriver.decrementSkipCount();
Decrements the number of snippets to be skipped.
getDynamicContext
const dynamicContext = flowDriver.getDynamicContext();
Returns the driver's dynamic context.
setDynamicContext
flowDriver.setDynamicContext({
myKey: myValue
});
Sets the dynamic context, it's an alternative to pass the dynamic context in the driver's constructor.
stackUp
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.
isStacked
const isStacked = flowDriver.isStacked('mySnippet1');
Returns a boolean indicating if the snippet was stacked up.
resetStack
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.
setFlushFunction
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.
flush
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.
ignore
flowDriver.ignore('mySnippet1', 'mySnippet2');
Ignores the specified snippets in the flow execution.
isIgnored
const isIgnored = flowDriver.isIgnored('mySnippet1');
Returns a boolean indicating if the snippet will be ignored.
removeIgnored
flowDriver.removeIgnored('mySnippet1', 'mySnippet2');
Removes specified snippets from the list of ignored snippets.
FlowTracer
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.
markMemoryUsage
flowTracer.markMemoryUsage('myKey');
Marks a key to be memory usage traced.
calculateMemoryUsage
flowTracer.calculateMemoryUsage('myKey');
Calculates a key memory usage tracing.
getCPUCoresAverage
FlowTracer.getCPUCoresAverage();
Returns the CPU cores usage average, this function is used internally by the methods that trace CPU usage.
markCPUUsage
flowTracer.markCPUUsage('myKey');
Marks a key to be CPU usage traced.
calculateCPUUsage
flowTracer.calculateCPUUsage('myKey');
Calculates a key CPU usage tracing.
markTimespan
flowTracer.markTimespan('myKey');
Marks a high resolution (bigint) realtime start timespan.
calculateTimespan
flowTracer.calculateTimespan('myKey');
Calculates a high resolution (bigint) realtime end timespan and elapsed time.
markTracing
flowTracer.markTracing('myKey');
Marks a key to be traced (CPU, memory and timespan).
calculateTracing
flowTracer.calculateTracing('myKey');
Calculates a key tracing (CPU, memory and timespan).
getTracing
const tracing = flowTracer.getTracing();
Returns all traced keys and their values.
RuntimeError
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.
GenericFlow
const { GenericFlow } = require('naxis');
const flow = new GenericFlow();
GenericFlow is a class to represent and handle a snippets flow execution.
use
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.
use
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');
}
License
This project is licensed under the Apache-2.0 license.
Copyright © 2019 Victor França Lopes
5 years ago