libharmonia
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.
Usage
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. Sender
and 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 Listener
.
Let's create both in both Typescript and ES7 code.
Sender
Our sender is going to send a math problem to a service called math
that can return the
solution.
; // 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
API
Error handling
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
a try ... catch
statement, otherwise your errors may be swallowed.
new Harmonia(options)
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 messengerConfig
,
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
other systems.
Usage
; // Always try..catch as errors are thrown not returnedtry catch harmoniaError
harmonia.request(callback)
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.
Usage
// Always try..catch as errors are thrown not returnedtry catchrequestError
harmonia.message(requestId, message)
This is an async
function (a Promise) that will return the response from the remote service.
Usage
// Always try..catch as errors are thrown not returnedtry catchmessageError
The response from harmonia.message
will always match MessageResponse
which you can see below.
MessageResponse
harmonia.addListener(pattern, callback(message, error))
To register a listener you add the action and callback function with a call to harmonia.addListener
.
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 message
and error
as arguments.
Then call harmonia.addListener
, specify the pattern to match on, and then the callback function.
Usage
harmonia.addListener, sum;
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.
harmonia.addListener , ;
We use 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.
Install
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.
Standalone
With npm installed, run
$ npm install libharmonia
Or with yarn
$ yarn add libharmonia
Acknowledgments
seneca.js
is a similar an far less opinionated module, that was the primary inspiration
for libharmonia
patrun
for an excelent pattern matching library.
See Also
License
ISC License (ISC)
Copyright (c) 2017, Owen Kelly owen@owenkelly.com.au
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.