Skip to content

Instantly share code, notes, and snippets.

@michaelfig
Last active December 20, 2019 04:34
Show Gist options
  • Save michaelfig/6d199ea95eab3ebdb918359612123a3e to your computer and use it in GitHub Desktop.
Save michaelfig/6d199ea95eab3ebdb918359612123a3e to your computer and use it in GitHub Desktop.
Use a Node.js worker thread with a FIFO to implement a service call that returns to the main thread synchronously.
const {
Worker,
isMainThread,
parentPort,
MessageChannel,
receiveMessageOnPort,
} = require('worker_threads');
const fs = require('fs');
const FIFO_NAME = '/tmp/wake-main-thread';
if (isMainThread) {
console.log('starting main thread');
const { execSync } = require('child_process');
execSync(`rm -f ${FIFO_NAME}; mkfifo ${FIFO_NAME}`);
let count = 0;
setInterval(() => {
if (count ++ >= 3) {
process.exit(0);
}
console.log('counter is alive', count);
}, 1000);
const worker = new Worker(__filename);
// We need to create a new MessageChannel because the default
// worker port cannot be reified as an argument to receiveMessageOnPort;
const ioChannel = new MessageChannel();
worker.postMessage(ioChannel.port1, [ioChannel.port1]);
console.log('sending request to worker');
ioChannel.port2.postMessage({id: 1, arg: 'Hello, world!'});
let reply = receiveMessageOnPort(ioChannel.port2);
while (reply === undefined) {
console.log('blocking main thread on', FIFO_NAME);
fs.readFileSync(FIFO_NAME); // block
console.log('waking main thread from', FIFO_NAME);
reply = receiveMessageOnPort(ioChannel.port2);
}
console.log('main thread received', reply);
} else {
parentPort.on('message', port => {
// New IO instance.
port.on('message', async request => {
// Simulate some async work.
await new Promise(resolve => setTimeout(resolve, 1500));
const reply = {id: request.id, reply: `got: ${request.arg}`};
// Return the message, and wake the main thread if it isn't already.
port.postMessage(reply);
fs.writeFileSync(FIFO_NAME, ''); // unblock
});
});
}
@michaelfig
Copy link
Author

michaelfig commented Dec 20, 2019

The output, under MacOS (I'd expect Linux would work too):

soil:cosmic-swingset michael$ node blocking-the-main-thread.js 
starting main thread
sending request to worker
blocking main thread on /tmp/wake-main-thread
waking main thread from /tmp/wake-main-thread
main thread received { message: { id: 1, reply: 'got: Hello, world!' } }
counter is alive 1
counter is alive 2
counter is alive 3
soil:cosmic-swingset michael$ 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment