npm install resoluteResolute implements the servicebus pattern - publishing and subscribing to events and sending commands.
The non-blocking nature of Node.js means we can perform atomic operations on the backing stores. We are also able to service requests while waiting for messages to send and be received.
Resolute expects a filesystem fsync to result in a disaster recoverable change. Network mounts and other exciting filesystems may not promise recoverable changes after an fsync. Resolute works best when working on a local harddrive.
Shulz creates lock files along side the hashmaps to warn against more than once process accessing the same store. Shulz and seuss expect to be the only process operating on their disk based storage.
If a servicebus process was not shut down correctly the lock files need to be removed before it can start again. If you are sure the process has failed run resolute unlock in the datadir. Once the lock files have been removed the process can be restarted. In an unlocked state stores can be administered to remove or update messages, adjust subscribers or purge and start the servicebus from scratch.
js
var resolute = require 'resolute'
var bus = resolute({
bind: 'tcp://127.0.0.1:12345',
datadir: process.cwd()
});setInterval(function() {
console.log('CLOUDY');
bus.publish('weather update', 'CLOUDY');
}, 1000);
process.on('SIGINT', function() {
bus.close();
process.exit(0);
});
`
Subscriber
`js
var resolute = require 'resolute'
var bus = resolute({
bind: 'tcp://127.0.0.1:54321',
datadir: process.cwd()
});bus.subscribe('tcp://127.0.0.1:12345', 'weather update');
bus.every('weather update', function(p, cb) {
console.log(p);
cb();
});
var seensigint = false;
process.on('SIGINT', function() {
if (seensigint) {
console.log('Exiting without confirming unsubscription');
bus.close();
process.exit(0);
}
seensigint = true;
console.log('Attempting to unsubscribe');
bus.unsubscribe('tcp://127.0.0.1:12345', 'weather update', function() {
bus.close();
process.exit(0);
});
});
`
Command line tool
`console
Usage: resolute [command]Show the status of a resolute data directory
Commands:
status Show an overview
unlock Unlock all maps
keys Print a list of subscription keys
subscribers Print a list of unique subscribers
incoming Print all incoming messages
outgoing Print all outgoing messages
Options:
-h Display this usage information
-v Display the version number
`Example scenario
You have two servers - a webserver hosting a website and a backend server that sends emails. In our scenario users sign up on the website and welcome emails are sent from the backend server to greet the new users. A business evaluation has indicated that users should still be able to sign up even if emails are not able to be sent. The welcome emails can queue until emails can be sent. Additionally the email service should stay running during a website outage as it also sends important emails from other systems.Logically there may be several independent actions initiated whenever a user signs up to the website. We may want to add more actions for each user signup in the future. Architecturally it is easier if the webserver has no knowledge of the steps occuring after a user has signed up and the subscribing services register their interest in the
signup event.We require some sort of coordination between the webserver and the email service. Many message buses require a third server to broker the messages between webserver and email service. However now there is a third server that requires additional uptime guarantees. A more robust solution involves the webserver talking directly to the backend server. This pattern scales well and does not require a central broker that requires high uptime.
Web -> Outgoing
Each step in the process needs a save state in case of power failure or other issue. We will start with the signup submit button. This button sends a post request to the Node.js webserver which may be running something like expressjs. The hander for the post may update a database and perform other actions like validation. At some point it will want to publish a notification to anyone who is interested that a new user has signed up. This calls resolute.publish which writes synchronously to the harddrive and returns immediately. The expressjs handler can return a success message and the user is able to continue on with their actions. The webserver can crash any time after the publish has been written and the publish will be retried when the servicebus is restarted.Email Service -> Web
The email service knows it needs to receive messages from the website. It has an event key and the tcp host and port address of the website servicebus socket. To receive messages from the website the email service needs a servicebus. Each instance of resolute includes sending and receiving functionality. The email service sends a message using the normal resolute protocol to the website providing a return address. This message asks the website to subscribe the email service to all signup events. If the website servicebus is down the subscribtion message waits in the outgoing queue until it can be successfully delivered. The email service will only stop trying to send the subscription message once it has a successful reply from the website. Once subscribed the website knows every signup event` needs to be sent to the email service.This may change in the future to track each message independently.