Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
nats-hemera
Advanced tools
A Node.js microservices toolkit for the NATS messaging system
Hemera is a small wrapper around the NATS driver. We want to provide a toolkit to develop micro services in an easy and powerful way. We use bloom filters to provide a pattern matching RPC style. You don't have to worry about the transport. NATS is powerful.
With Hemera you have the best of both worlds. Efficient pattern matching to have the most flexibility in defining your RPC's. It doesn't matter where your server or client lives. You can add the same add as many as you want on different hosts to ensure maximal availability. Thanks to the Request Reply pattern you can work with that as if you do a normal http request. The only dependency you have is a single binary of 7MB. Mind your own business NATS do the rest for you:
topic:auth:germany
+ Hemera = Pattern-driven micro services.
We use the Request Reply concept to realize this toolkit. Request Reply
npm i nats-hemera
'use strict';
const Hemera = require('hemera');
const nats = require('nats').connect(authUrl);
const hemera = new Hemera(nats, { logLevel: 'info' });
hemera.ready(() => {
hemera.add({ topic: 'math', cmd: 'add' }, (resp, cb) => {
cb(null, resp.a + resp.b);
});
hemera.add({ topic: 'email', cmd: 'send' }, (resp, cb) => {
cb();
})
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 2, timeout$: 5000 }, (err, resp) => {
console.log('Result', resp);
});
//Without callback
hemera.act({ topic: 'email', cmd: 'send', email: 'foobar@mail.com', msg: 'Hi' });
});
Add: Define you implementation.
Act: Start a request
Topic: The subject to subscribe. The smallest unit of Hemera. It's kind of namespace for your service. If you want to scale your service you have to create a second instance of your service. If you just want to scale a method you have to subscribe to a different subject like math:additions
because any subscriber have to contain the full implementation of the service otherwise you can run into a PatternNotFound
exception.
hemera.add({ topic: 'math', cmd: 'add' }, (resp, cb) => {
cb(null, resp.a + resp.b);
});
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 }, (err, resp) => {
console.log(resp); //2
});
A match happens when all properties of added pattern matches with the one in the passed object.
hemera.add({ topic: 'math', cmd: 'add' }, (resp, cb) => {
cb(resp.a + resp.b)
});
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 });
hemera.add({ topic: 'math', cmd: 'add', foo: 'bar' }, (resp, cb) => {
cb(resp.a + resp.b)
});
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 });
hemera.add({ topic: 'math', cmd: 'add' }, (resp, cb) => {
cb(new CustomError('Invalid operation'));
});
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 }, (err, resp) => {
err instanceOf CustomError // true
});
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 }, (err, resp) => {
err instanceOf TimeoutError // true
});
Fatal errors will crash your server. You should implement a gracefully shutdown and use a process watcher like PM2 to come back in a clear state. Optional you can disable this behavior by crashOnFatal: false
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 }, (err, resp) => {
throw new Error('Upps');
});
hemera.add({ topic: 'math', cmd: 'add' }, (resp, cb) => {
err instanceOf FatalError // true
});
const hemera = new Hemera(nats, { logLevel: 'info' });
hemera.events.on('error', ...)
hemera.events.on('disconnect', ...)
hemera.events.on('connect', ...)
//see NATS driver for more events
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1, timeout$: 5000 }, (err, resp) => {
});
this
If you want to transfer metadata to a service you can use the meta$
property before sending. It will be passed in all nested act
.
E.g. you can add a JWT token as metadata to express if your action is legitimate.
hemera.add({ topic: 'math', cmd: 'add' }, function (resp, cb) {
//Access to metadata
let meta = resp.meta$
cb(null, resp.a + resp.b);
});
Will set the metadata only for this act
and all nested act
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1, meta$: { a: 'test' } }, function (err, resp) {
this.act({ topic: 'math', cmd: 'add', a: 1, b: 5 });
});
Will set the metadata on all act
hemera.meta$.token = 'ABC1234'
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1}, function (err, resp) {
//or
this.meta$.token = 'ABC1234';
this.act({ topic: 'math', cmd: 'add', a: 1, b: 5 });
});
If you want to set a context across all act
you can use the context$
property.
hemera.context$.a = 'foobar';
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1 }, function (err, resp) {
this.act({ topic: 'math', cmd: 'add', a: 1, b: 5 }, function (err, resp) {
this.context$.a // 'foobar'
});
});
If you want to set a context only for this act
and all nested act
hemera.act({ topic: 'math', cmd: 'add', a: 1, b: 1, context$: 1 }, function (err, resp) {
this.act({ topic: 'math', cmd: 'add', a: 1, b: 5 }, function (err, resp) {
this.context$ // 1
});
});
In any act or add you can access the property this.parentId$
or this.requestId$
to get information about your current or parent call. You can listen on the inbound
event to get detail information about you calls this includes transport-latency, response/request timing and durations.
result: 10
error: null
response$: {
"startTime": 456447212806,
"endTime": 456447216611,
"duration": 3805
}
meta$: {
span: 3 //This request is the third node in the transaction.
},
request$: {
"id": "32HDHW7G1WRMNF2B6Y3KOD",
"parentId": "32HDHW7G1WRMU0ZHX9J864",
"traceId": "32HDHW7G1WRMU0ZHX9J861",
"startTime": 456447211853,
"endTime": 456447216759,
"transportLatency": 953,
"duration": 4906,
"pattern": "a:1,b:3,cmd:sub,topic:math"
}
hemera.on('outbound', (msg) => {
console.log('Outbound', msg)
})
hemera.on('inbound', (msg) => {
console.log('Inbound', msg)
})
Times are represented in nanoseconds.
Hemera includes a payload validator called parambulator But you can also use different validators e.g Joi example
hemera.add({
topic: 'math',
cmd: 'add',
a: {
type$: 'number'
}
}, (resp, cb) => {
cb(null, {
result: resp.a + resp.b
});
});
Handling
hemera.act({ topic: 'math', cmd: 'add', a: '1' }, function (err, resp) {
err instanceOf PayloadValidationError //true
});
let myPlugin = function (options) {
let hemera = this;
hemera.add({
topic: 'math',
cmd: 'add'
}, (resp, cb) => {
cb(null, {
result: resp.a + resp.b
});
});
};
hemera.use({ plugin: myPlugin, attributes: { name: 'myPlugin' }, options: { } })
Hemera used Pino logger by default but you can also use your own example
Your custom logger have to support following log levels.
['info', 'warn', 'debug', 'trace', 'error', 'fatal']
const hemera = new Hemera(nats, { logLevel: 'info' });
[2016-11-17T21:04:47.608Z] INFO (app/18196 on starptech): ACT
topic: "math"
cmd: "add"
a: 1
b: 2
[2016-11-17T21:04:47.613Z] INFO (app/18196 on starptech): ACT_RESP
topic: "math"
cmd: "add"
a: 1
b: 2
time$: 2
Format: JSON
{
"pattern": "<object>",
"meta$": "<object>",
"request$": "<object>"
}
{
"result": "<any>",
"error": "<serialized_error>",
"meta$": "<object>",
"response$": "<object>"
}
Think in small parts. A topic is like a service. You can define a service like auth
which is responsible for authenticate users.
This service has actions like:
hemera.add({ topic: 'auth', cmd: 'authenticate' })
hemera.add({ topic: 'auth', cmd: 'passwordReset' })
...
Now your service is scaled.
node service.js
node service.js
Now your service is fault-tolerant.
var servers = ['nats://nats.io:4222', 'nats://nats.io:5222', 'nats://nats.io:6222'];
var nc = nats.connect({'servers': servers});
new Hemera(nc);
https://www.youtube.com/watch?v=NfL0WO44pqc
http://nats.io/documentation/faq/
The simplicity and focus of NATS enables it to deliver superior performance and stability with a lightweight footprint. It has the potential of becoming the de-facto transport for microservice architectures and event driven systems in this new era.
Asim Aslam, Creator of Micro
"I discovered NATS for its performance, and stayed for its simplicity. Itβs been a wonderfully reliable layer that connects our microservice architecture at Pressly. The source is easily readable and approachable, and the future developments keep me excited!
Peter Kieltyka - CTO, Pressly
Set the path to the gnatsd
before start testing.
npm run test
Easy and beautiful tool to monitor you app. hemera-board
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
We use SemVer for versioning. For the versions available, see the tags on this repository.
See also the list of contributors who participated in this project.
This project is licensed under the MIT License - see the LICENSE.md file for details
Seneca - A microservices toolkit for Node.js.
FAQs
The core package of hemera
The npm package nats-hemera receives a total of 1,455 weekly downloads. As such, nats-hemera popularity was classified as popular.
We found that nats-hemera 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
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.