Enter the Wormhole; IPC goodness
This post and the example in it have been updated to match version 1.x.x.
Node’s child_process
module allows you to spawn and fork new processes, optionally with a built-in Inter-Process Communication (IPC) channel. This is an easy way to communicate with the child process, and valuable on its own in many situations. But it’s not very developer-friendly.
Wait, scratch that, its very developer-friendly. It’s just not… easily and repeatably usable. You will need to define your own JSON-based protocol, which can become tedious if you need to do this often. Addition: it’s not really necessary to define your own protocol: primitive values can be sent too, albeit without metadata.
So, to stay in keeping with DRY and KISS I decided to make a little module that does most of the heavy lifting for me. Note that there are probably dozens of modules out there that do what I did and probably better, but that doesn’t take the fun out of building it. It’s simple and it works, so I’m sure there are applications.
I wanted a couple of things:
- A way to notify the other end of the link of events that have happened
- A way to call commands on the remote end and receive a result back (RPC-like behavior)
To satisfy these requirements I built wormhole. It’s designed to work with Node.JS’s child_process
and process
, and provides what I was looking for.
Installing it is super simple:
npm i @art-of-coding/wormhole --save
How do you use it, you ask? It’s fairly simple – just fork a child process that uses wormhole, and you can send events and call commands!
In the example below we fork a child process, and both processes use wormhole. This allows them to send events and call remote commands. All features are supported in either direction (it’s bidirectional).
The master process:
const childProcess = require('child_process') const Wormhole = require('@art-of-coding/wormhole') const child = childProcess.fork('./my-child.js') const wormhole = new Wormhole(child) // Register a `startup` event handler wormhole.events.on('startup', () => { console.log('received startup event!') }) // Register an `add` command wormhole.define('add', function (a, b) { return a + b }) // Send the `quit` event to the child setTimeout(() => wormhole.event('quit'), 5000)
The child process:
const Wormhole = require('@art-of-coding/wormhole') // Without the `channel` argument, `process` is selected by default const wormhole = new Wormhole() // Register a `quit` event handler wormhole.events.once('quit', () => { process.exit(-1) }) // Send an event wormhole.event('startup') // Call a remote command wormhole.command('add', 5, 6).then(result => { console.log(`5 + 6 = ${result}`) })
As you can see for yourself, using it could not be easier!