Scalability is a type-safe service scaling facility built on Network-Services.
Scalability provides a simple and intuitive API for scaling Node.js modules using Worker threads. You can create a Service App in your scaled module and call its methods from the main thread using a Service API. Conversely, methods can be called in the main thread from scaled modules in the same way.
Scalability allows you to easily transform your single threaded application into a multithreaded one.
- Call methods on a Service App running in a Worker thread using a type-safe API: code completion, parameter types, and return types.
- Return values and Errors are marshalled back to the caller.
- Infinite property nesting; you can use a Service API to call nested properties on a Service App at any depth.
- Bi-directional asynchronous RPC - communication goes both ways - Scalability allows for calls from the main thread to a Worker and from a Worker to the main thread.
npm install scalability
Scalability is an extension of the Network-Services RPC Service facility; hence, the concepts that it introduces are Network-Services concepts e.g., Services, Service Apps, and Service APIs.
Please see the Network-Services documentation if you would like to learn more about these concepts.
A Scalability application consists of a main thread (e.g., index.js
) and a scaled module (e.g., service.js
). In this example the module that runs in the main thread is named index.js
and the module that will be scaled is named service.js
.
This is the module that runs in the main thread.
Import the createService
and createWorkerPool
helper functions and the type of the service application (i.e., Greeter
) that will run in the Worker thread.
import { createService, createWorkerPool } from 'scalability';
import { Greeter } from './service.js';
const workerPool = createWorkerPool({
workerCount: 10,
workerURL: './dist/service.js'
});
await new Promise((r) => workerPool.on('ready', r));
The greeter
object will support code completion, parameter types, and return types.
const service = createService(workerPool);
const greeter = service.createServiceAPI<Greeter>();
The greeter.greet
method returns a promise because it is called asynchronously using a MessagePort
.
const results = [];
for (let i = 0; i < 100; i++) {
results.push(greeter.greet('happy'));
}
const result = await Promise.all(results);
console.log(result);
This is the scaled module specified in the options of the WorkerPool
constructor. It contains the Greeter
Service App.
import { createPortStream, createService } from 'scalability';
export class Greeter { // Create a friendly Greeter Application.
greet(kind: string) {
for (let now = Date.now(), then = now + 100; now < then; now = Date.now()); // Block for 100 milliseconds.
return `Hello, ${kind} world!`;
}
}
This adapter will wrap the Worker thread's parentPort
in a stream.Duplex
in order for it be used by Network-Services.
const portStream = createPortStream();
const service = createService(portStream);
service.createServiceApp(new Greeter());
That's all it takes to scale this Greeter
application.
stream
<WorkerPool | PortStream>
An instance of aWorkerPool
or an instance of aPortStream
. This is a type narrowed version of the Network-ServicescreateService
helper function. This helper function will accept either aWorkerPool
or aPortStream
as an argument, both of which arestream.Duplex
.- Returns:
<Service>
app
<object>
An instance of your application.options
<ServiceAppOptions<T>>
paths
<Array<PropPath<Async<T>>>>
AnArray
of property paths (i.e., dot-pathstring
s). If defined, only property paths in this list may be called on the Service App. Each element of the Array is aPropPath
and aPropPath
is simply a dot-pathstring
representation of a property path. Default:undefined
.
- Returns:
<ServiceApp<T>>
options
<ServiceAPIOptions>
timeout
<number>
Optional argument in milliseconds that specifies thetimeout
for function calls. Default:undefined
(i.e., no timeout).
- Returns:
<Async<T>>
AProxy
of type<T>
that consists of asynchronous analogues of methods in<T>
.
options
<WorkerPoolOptions>
workerCount
<number>
Optional argument that specifies the number of worker threads to be spawned.workerURL
<string | URL>
The URL or path to the.js
module file. This is the module that will be scaled according to the value specified forworkerCount
.restartWorkerOnError
<boolean>
A boolean setting specifying if Workers should be restarted onerror
. Default:false
workerOptions
<worker_threads.WorkerOptions>
Optionalworker_threads.WorkerOptions
to be passed to each Worker instance.duplexOptions
<stream.DuplexOptions>
Optionalstream.DuplexOptions
to be passed to thestream.Duplex
i.e., the parent class of theWorkerPool
.
- Returns:
<WorkerPool>
A WorkerPool
wraps the MessagePorts
of the Worker threads into a single stream.Duplex
. Hence, a WorkerPool
is a stream.Duplex
, so it can be passed to the Network-Services createService
helper function. This is the stream adapter that is used in the module of the main thread.
options
<stream.DuplexOptions>
Optionalstream.DuplexOptions
to be passed to thestream.Duplex
i.e., the parent class of thePortStream
.
A PortStream
wraps the parentPort
of the Worker thread into a stream.Duplex
. Hence, a PortStream
is a stream.Duplex
, so it can be passed to the Network-Services createService
helper function. This is the stream adapter that is used in the Worker module.