App Masters

App Masters

  • English
  • Português

›Backend

App Masters - Core

  • Home
  • Content

Backend

  • Node Express
  • Node Worker Threads

Database

  • GraphQL

Javascript Fundamentals

  • Asynchronous Javascript
  • Typescript

Design Patterns

  • Presentational Container Design Pattern

Frontend

  • AMP (Accelerated Mobile Pages)
  • Bubblewrap
  • Gatsby.js
  • Next.js
  • PWA
  • Styled Components

Mobile

  • React Native
  • Store Testing

Server

  • Netlify

Testing

  • Cypress
  • Jest

Design

  • Human Interface
  • Material Design

Tools

  • Bitrise
  • Docker

Node Worker Threads

What is it

worker_threads is a module that enables the use of thread that executes JavaScript in parallel.

Although Node can handle several simultaneous requests very well, problems start to appear when your requests need to perform intensive operations that use a lot of the CPU time. By default, your node application run in a single thread, and CPU-heavy methods can block Node main loop and prevent it from answering other users' requests and cause them to wait for the operation to finish before their requests can be processed.

In this scenario, a good way to solve the problem is to offload the CPU-heavy processing to other threads, using the worker_threads module.

When using Workers the process changes slightly:

Schema with Worker Threads

How to use it

To use the final worker_threads API you need to use Node 12 LTS or newer. Its API consists in three main classes:

  • Worker: Class used to instantiate a new thread that will run your script;
  • MessageChannel: Used to create a communication channel between the instantiated threads; and
  • MessagePort: Used to send and receive events and messages to other threads.

Here is a simple example of the use of the threads:

// index.js
import { Worker } from 'worker_threads';

export default processAsync = (script) => {
  return new Promise((resolve, reject) => {
    // Instantiate a new thread executing the 'worker.js' file
    const worker = new Worker('worker.js', {
      workerData: script
    });
    // Setup the listeners using the default 'MessagePort' instance
    worker.on('message', resolve);
    worker.on('error', reject);
    worker.on('exit', (code) => {
      if (code !== 0)
        reject(new Error(`Worker stopped with exit code ${code}`));
    });
  });
};

// worker.js
import { parentPort, workerData} from 'worker_threads';
import { process } from 'some-cpu-heavy-processing-library';

const script = workerData;
parentPort.postMessage(parse(script));

Note that by default, when instantiating a worker, it creates one MessageChannel between the parent and child thread. Its MessagePorts are available through worker in the parent thread and parent port in the instantiated thread.

You can easily create new MessageChannels:

const { port1, port2 } = new MessageChannel();
port1.on('message', (message) => console.log('received', message));
port2.postMessage({ foo: 'bar' });

You can also pass new ports to existing threads:

worker1 = new Worker(...);
worker2 = new Worker(...);

const { port1, port2 } = new MessageChannel();
worker1.postMessage({ port: port1 }, [port1]);
worker2.postMessage({ port: port2 }, [port2]);

How we use it today

We are currently using the worker_threads module to offload the cpu heavy operations from the main thread of our application. The Phormar project has an implementation of a wrapper around the worker_threads to handle thread reinitialization, error handling, and communication. You can see it here.

How to learn more

Useful Material

  • Worker Threads Oficial Documentation
  • Understanding Worker Threads in Node.js
  • Worker Threads with TypeScript - Web Archive
  • Sending data between Worker Threads - Web Archive
  • Video - Understanding V8 Event Loop
← Node ExpressGraphQL →
  • What is it
  • How to use it
  • How we use it today
  • How to learn more
    • Useful Material
App Masters
App masters
Content
More
BlogGitHub
Copyright © 2022 App Masters