Clustered application creation toolkit
Amino is a toolkit for building scalable, fault-taulerant apps in Node.js. By using its simple API, you can harness the power of pub/sub, job queuing, and auto-load-balancing without any of the fuss and dependence on particular technologies.
The API provides:
- pubsub -- Use
amino.publish()
andamino.subscribe()
to send events between nodes in your cluster. (default driver: redis) - queue -- Use
amino.queue()
andamino.process()
to queue jobs and process them. (default driver: amqp, i.e. RabbitMQ) - request -- Use
amino.request()
andamino.respond()
to easily create REST APIs with auto-load-balancing and failover. (default driver: HTTP, uses pub/sub) - service -- Advanced: Use
amino.createService()
to register a service, and receive a port to listen on. This allows you to create generic TCP services.
If you have redis and RabbitMQ servers running locally on the default ports, all you need to get started is:
$ npm install amino
var amino = require('amino');
// Use amino API
Amino uses a configuration file (in JSON format) to determine what drivers to use. It looks
like this (default conf located in etc/amino.json
)
{
"amino": {
"pubsub": {
"driver": "redis",
"options": {
"nodes": ["localhost:6379"]
}
},
"queue": {
"driver": "amqp",
"options": {
"url": "amqp://localhost"
}
},
"request": {
"driver": "http"
},
"range": [50000, 60000]
}
}
To override this, you can do:
$ node myapp.js --conf /path/to/my/amino.json
Or to use an app-level conf, copy amino.json
to an etc
folder in your process's
cwd
. Alternatively, it can be named app.json
or conf.json
.
Or to use a system-wide conf, you can put one at /etc/amino.json
.
At the moment, there are no other selectable drivers. More coming soon!
publisher.js
// Tell other nodes my name when I start.
var amino = require('amino');
amino.publish('myname', 'amino99');
subscriber.js
// Greet other nodes as they come up.
var amino = require('amino');
amino.subscribe('myname', function(name) {
console.log('hello, ' + name + '!');
});
order-sprocket.js
// Add sprocket request to a queue. These things take time.
var amino = require('amino');
amino.queue('orders', {type: 'sprocket-b', spokes: 5});
console.log('Your order is processing!');
make-sprockets.js
// Fulfill sprocket requests.
var amino = require('amino');
amino.process('orders', function(order, next) {
makeSprocket(order, function(err, sprocket) {
if (sprocket) {
console.log('Created sprocket with id ' + sprocket.id);
}
next(err);
});
});
serve-sprocket.js
// Create a sprocket service.
var amino = require('amino');
// "sprockets" will be our virtual host. We'll also tag it with
// a version (2.1.0) for requests to filter by.
amino.respond('[email protected]', function(router, spec) {
// router is a director router.
// @see https://github.com/flatiron/director
router.get('/:id', function(id) {
// amino adds the helpers json(), text(), and html().
this.res.json({id: id});
});
});
get-sprocket.js
// Request a sprocket from the sprocket service.
var amino = require('amino');
// amino.request() is the same as github.com/mikeal/request, except
// it can handle the amino:// protocol, which uses virtual hosts defined
// with amino.respond().
amino.request('amino://sprockets/af920c').pipe(process.stdout);
// To limit the request to hosts running sprockets v2.x, we can use a special header:
amino.request({url: 'amino://sprockets/af920c', headers: {'x-amino-version': '2.x'}}).pipe(process.stdout);
create-service.js
// Create a TCP service which sends "hello world"
var amino = require('amino')
, net = require('net');
var server = net.createServer(function(socket) {
socket.write("hello world");
});
var service = amino.createService('[email protected]', function(spec) {
server.listen(spec.port);
console.log('listening on port ' + spec.port);
});
use-service.js
// Connect to the hello service
var amino = require('amino')
, net = require('net')
, req
, socket
;
req = amino.requestService('hello', '1.x');
req.on('spec', function(spec) {
socket = net.createConnection(spec.port);
socket.on('connect', function() {
console.log('connected to hello service version ' + spec.version);
});
socket.setEncoding('utf8');
socket.on('data', function(data) {
// data should be "hello world"
console.log(data);
});
});