thalassa
v0.4.1
Published
A lightweight service registry using Redis inspired by Seaport
Downloads
10
Readme
Thalassa
Thalassa is a lightweight service registry build primarily on node.js, Redis and Axon, inspired by Seaport. Thalassa is actually a system of components primarily geared to enable continuous deployment scenarios through dynamic configuration of HAProxy load balancers and seamless, no connection drop A/B deploys.
This is the central module that includes the server registry and client. The registry uses a ping and expiration type approach. Clients register with the server and pass an optional secondsToExpire
property telling the server when it is acceptable to expire the registration if the registration is not updated in that time. There is an internal "reaper" function that runs periodically to reap expired registrations. More on that later.
History
Thalassa is a second generation system, superseding what was otherwise knows as "Spindrift" inside of Pearson. Spindrift leaned heavily on @substack's Seaport module. Incidentally, Seaport was the original inspiration for the aquatic theme of Spindrift and Thalassa.
In Greek mythology, Thalassa was the primeval spirit of the sea. In the fables of Aesop, Thalassa appears as a woman formed of sea water rising up from her native element. Thalassa was depicted in Roman-era mosaics as a woman half submerged in the sea, with crab-claw horns, clothed in bands of seaweed, and holding a ship's oar.1
Installation
npm install thalassa
or globally
npm install -g thalassa
Running the Server
The Thalassa server and client may be run from the command line or embedded as a module within your application.
Running from Command Line
Assuming Redis is installed and running, start the thalassa server with default options:
./node_modules/.bin/thalassa-server --debug
or
thalassa-server --debug
Server Command Line Options
thalassa-server --help
Options:
--host host to bind to [default: "127.0.0.1"]
--port port to bind to for axon socket [default: 5001]
--apihost host to bind to [default: "127.0.0.1"]
--apiport port to bind to for http api [default: 9000]
--redisHost Redis host [default: "127.0.0.1"]
--redisPort Redis port [default: 6379]
--redisDatabase Redis database to select [default: 0]
--reaperFreq Reaper frequency (ms) [default: 2000]
--debug enabled debug logging
Server as an Embedded Module
The same options above (except debug
) may be passed by properties set in the opts
object. For example using new Thalassa.Server(opts)
:
var Thalassa = require('thalassa');
var server = new Thalassa.Server({
port: 4444,
apiport: 4445,
host: 'localhost'
});
In addition opts.log
may be optionally set to your own function to handle logging. opts.log
expects this signature: function log (level, message, object){}
. level
will be one of debug
, info
, and error
. message
is a string and object
is an optional object with key value pairs. Of opts.log
is not passed, the module will be quiet.
Running the Client
The client can be run any of three ways.
- From the command-line
- As a module
- Over HTTP
Running Client from Command Line
Why would you do this? Let's say you have an existing legacy Java application that you'd rather not change. You can create a sister service that invokes the command line client to register the service on it's behalf.
For example, if Thalassa is installed globally (other wise `./node_modules/.bin/thalassa-client):
thalassa-client --register [email protected]:8080 --debug
This registers the application named my app
at version 1.0.0
that's on the current host on port 8080
. The client will continue to ping the Thalassa server with updates.
Client Command Line Options
thalassa-client --help
Options:
--host thalassa host [default: "127.0.0.1"]
--port thalassa axon socket port [default: 5001]
--apiport thalassa http api port [default: 9000]
--register [email protected]:port,[email protected]:port [required]
--secsToExpire default time in seconds for a thalassa registration to be valid [default: 60]
--updateFreq time frequency in ms to ping the thalassa server [default: 20000]
--updateTimeout time in ms to wait for a registrion request to respond [default: 2500]
--debug enabled debug logging
Client as an Embedded Module
Using the client from within a node.js application to register your service is simple. Pass options via the opts
object like new Thalassa.Client(opts)
:
var Thalassa = require('thalassa');
var client = new Thalassa.Client({
port: 4444,
apiport: 4445,
host: 'localhost'
});
client.register('myapp', '1.0.0', 8080);
// start reporting registrations to the server
client.start();
// stop reporting registrations to the server
client.stop();
opts.log
may be passed just like the server.
updateSuccessful
and updateFailed
Events
The client will periodically check in with the Thalassa server according to opts.updateFreq
(default 20000ms). Each registration will product a updateSuccessful
or updateFailed
event to be emitted.
client.on('updateSuccessful', function () {}); client.on('updateFailed', function (error) {});
Subscriptions and online
and offline
Events
If running as a module, you also have access to subscribe
to online
and offline
events of certain applications. For example:
client.subscribe('myapp', '1.0.0');
client.on('online', function (registration) {});
client.on('offline', function (registration) {});
Alternatively for all versions of myapp
:
client.subscribe('myapp');
Or every service registration:
client.subscribe();
Querying Registrations
Also as a module, you can use the client API to query for registrations.
client.getRegistrations('myapp', '1.0.0', function (err, registrations) {
// registrations is an Array of Registrations
}
See the HTTP API section for the Registration
structure.
Metadata
You can also pass metadata with any registration as a fourth parameter. This can be any javascript object with properties. For example:
var meta = {
az: 'use1a',
size: 'm1.large',
foo: {
bar: 'baz'
}
};
client.register('myapp', '1.0.0', 8080, meta)
HTTP Client
The Thalassa server exposes a simple HTTP API so it's not necessary to use the node.js
client and any application that's capable of calling HTTP can participate as an application in the system. See the HTTP API.
HTTP API
GET /registrations/{name}/{version}
GET /registrations/{name}
GET /registrations
Return Registrations[]
of all registrations for the optionally provided name
and version
. /registrations
returns everything.
Registration
is defined in it's own module thalassa-registrations
. A typical registration looks like this:
{
"name": "myapp",
"version": "1.0.0",
"host": "192.168.8.106",
"port": 8080,
"lastKnown": 1378682020883,
"meta": {
"hostname": "mb-mbp.local",
"pid": 66593,
"registered": 1378682010864
},
"id": "/myapp/1.0.0/192.168.8.106/8080"
}
All times are in Unix time since epoch form.
The Thalassa client will automatically add meta.pid
and the server will automatically add registered
and hostname
if not provided. If a hostname
is not provided by the client, the IP will be used instead. Additionally, the Thalassa client will automatically set hostname
to require('os').hostname()
.
POST /registrations/{name}/{version}/{host}/{port}
Create or update a registration.
The BODY of the POST should be application/json
and will be added to meta
.
Additionally meta.secondsToExpire
should be set to explicitly set the expiration time of the registration. In essence you are telling the Thalassa server, if you don't hear back from me in so many seconds, expire my registration and fire an offline
event. This properly allows the client to tune how often they poll balanced with how long they are willing to accept stale registration data. If you set secondsToExpire
to 300
then you may poll every ten minutes, but if your service goes down or is underplayed, consumers won't know it for at most 300
seconds.
DELETE /registrations/{name}/{version}/{host}/{port}
Explicitly delete a registration, causing an offline
event.
STATUS status
Returns basic status with thalassa version, memory usage, uptime and registrationsPerSecond stats.
Known Limitations and Roadmap
Thalassa currently doesn't implement any type of authentication or authorization and at this point expects to be running on a trusted private network. This will be addressed in the future. Ultimately auth should be extensible and customizable. Suggestions and pull requests welcome!
License
Licensed under Apache 2.0. See LICENSE file.