An opinionated microservices framework for node.js and docker
Part of harmonia.systems,
libharmonia is the foundation of this opinionated system. It's role is
to provide a common inter-service messaging platform, deeply integrated with logging and tracing.
The harmonia.systems framework is one that explicity relys on pattern matching messages sent between services over a message queue.
libharmonia is written in Typescript, and can also be used with ES6/ES7 code.
You'll have the most fun with
async/await, with either Typescript or Babel. Keep an eye
on the NodeJS production releases for when a stable
async/await implementation hits NodeJS core.
In harmonia there are two roles that a system can perform.
Listener. By default, all
services can send out messsages as a
Sender, and with extra configuration they can also
listen for messages sent to them as a
Let's create both in both Typescript and ES7 code.
Our sender is going to send a math problem to a service called
math that can return the
;// Initialise Harmonia;// Lets create some numbers for this problem;;;// We wrap our harmonia.message calls in harmonia.request// This is essential to take advantage of the built in request tracing// harmonia.request is an async function that takes in a callback,// and passes a fresh requestId as the only parameter.// Then, all requests made inside our callback function, will// be linked together in our logging, allowing you to visualise// the flow of requests made throughout the system.;// Log our final resultconsole.log`( + ) * = `;// This should log:// (12 + 83) * 32 = 3,040
All of the public functions with
harmonia except the constructor
new Harmonia() are async functions (Promises).
All the public functions will throw an error if something went wrong, thus they must all be wrapped in
try ... catch statement, otherwise your errors may be swallowed.
The harmonia constructor lets you configure how this instance of harmonia is going to connect to your infrastructure.
Harmonia can connect to either an AMQP message queue like RabbitMQ or a lightweight high performance messaging bus like NATS.
It's also possible to supply your own or (third-party) sender and listener implementations, to connect
with a different messaging system. The sender and listener will both receive the same
and use the same messaging system. You can't send messages with AMQP, and listen for them with NATS.
At least, not within the same instance, you could setup two harmonia instances with different messaging
systems if you needed a bridge.
Harmonia by default will log to Graylog2 with
GELF, but again, you can pass through your own logging
implementation if you need to use something else. Graylog2 was chosen as it's a great open source
logging project, that works out of the both for debugging messages, but can also forward messages to
;// Always try..catch as errors are thrown not returnedtrycatch harmoniaError
Used to wrap
harmonia.message calls. This function
ensures a fresh requestId can be passed to
harmonia.message, it also clears out the internal state
that tracks the previous message -- allowing for detailed tracing of requests and messages.
// Always try..catch as errors are thrown not returnedtrycatchrequestError
This is an
async function (a Promise) that will return the response from the remote service.
// Always try..catch as errors are thrown not returnedtrycatchmessageError
The response from
harmonia.message will always match
MessageResponse which you can see below.
harmonia.addListener(pattern, callback(message, error))
To register a listener you add the action and callback function with a call to
The service is set in the constructor of the
harmonia instance, and can't be changed here.
First create an
async function which takes the
error as arguments.
harmonia.addListener, specify the pattern to match on, and then the callback function.
You can also pass a fat-arrow function callbacks as well. Though these will be much harder to unit test, and therfore are not reccomended.
patrun for pattern matching. Generally speaking the most specific pattern will always win.
Error handling in listener callbacks
The function that calls your callback will
try ... catch your function for any exceptions and pass
them back as an error. You don't explicity need to catch errors inside your callback, if you don't need
to handle it.
Generally you'll find it easier to start from one of our starterkits, as Harmonia is designed to be a framework to build upon.
TODO build and add a starter kit.
With npm installed, run
$ npm install libharmonia
$ yarn add libharmonia
seneca.js is a similar an far less opinionated module, that was the primary inspiration
patrun for an excelent pattern matching library.
ISC License (ISC)
Copyright (c) 2017, Owen Kelly email@example.com
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.