Understanding Actor Model for Node developer


Disclaimer: This is my personal learning experience with the Actor programming model.

How programming typically looks like

If you ask any web developer which programming language(s) they use, most will likely say they write code in Javascript/Typescript, PHP, Python, Go, or Ruby.

This code snippet shows how you can write a script that validates URLs using NodeJS.

const urlChecker = (url) => {
  fetch(url)
    .then((res) => {
      if (res.status == 200) {
        console.log(`${url} is valid`);
      }
    })
    .catch(() => {});
};

const urls = ["https://fadhil-blog.dev", "https://invalid.url"];

for (const url of urls) {
  urlChecker(url);
}

The code is simple and sweet. Basic programming 101, and this programming model works for most cases.

What is the Actor model

I’m skipping the formal introduction of the Actor model, which relates to the mathematical model. If you’re interested in that, you can read its history on Wikipedia

Actor is a concurrency model where you write software that each small unit of your system runs independently and communicates by passing messages. This way, each tiny Actor can run on all cores concurrently.

NodeJS has a library called nact that help Node developer to build an Actor-based system in Node. Here’s an example of the same script as above but written in the Actor model in Node:

const { start, dispatch, spawnStateless, spawn } = require("nact");
const system = start();

const spawnUrlChecker = (id) =>
  spawnStateless(
    system,
    (msg, ctx) => {
      const url = msg.url;

      console.log("validate URL", url);
      fetch(url)
        .then((res) => {
          if (res.status == 200) {
            dispatch(statefulUrls, { url: url });
          }
        })
        .catch(() => {});
    },
    `url-${id}`,
  );

const statefulUrls = spawn(
  system,
  (state = {}, msg, ctx) => {
    let urls = [];

    if (state.urls) {
      urls = [...state.urls, msg.url];
    } else {
      urls = [msg.url];
    }

    console.log(urls);
    return { ...state, urls: urls };
  },
  "stateful-urls",
);

let count = 0;

const urls = ["https://fadhil-blog.dev", "https://invalid.url"];

for (const url of urls) {
  count += 1;
  const urlChecker = spawnUrlChecker(count);
  dispatch(urlChecker, { url: url });
}

Running this code sample, you’ll get almost similar results as before. But what’s the difference? In this code sample, you’re

When using the actor model, people tend to spawn many of them, like thousands or millions.

Advantages