Scalability is a type-safe service scaling facility built on Network-Services.
npm install scalabilityScalability 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.
- Installation
- Concepts
- Usage
- API
- Support
``bash`
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.
`ts`
import { once } from "node:events";
import { createService, createWorkerPool } from "scalability";
import { Greeter } from "./service.js";
#### Create a pool of Workers consisting of 10 instances of the service.js module.
`ts`
const workerPool = createWorkerPool({
workerCount: 10,
workerURL: "./dist/service.js",
});
#### Wait for the Workers to come online.
`ts`
await once(workerPool, "ready");
#### Create a Service using the WorkerPool stream and a Service API of type Greeter.
The greeter object will support _code completion_, _parameter types_, and _return types_.
`ts`
const service = createService(workerPool);
const greeter = service.createServiceAPI
#### Call the greet method on the Greeter 100 times and log the results.
The greeter.greet method returns a promise because it is called asynchronously using a MessagePort.
`ts
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 the createPortStream and createService helper functions.
`ts`
import { createPortStream, createService } from "scalability";
#### Implement a Greeter service.
`tsHello, ${kind} world!
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 ;`
}
}
#### Create a PortStream adapter instance using the createPortStream helper function.
This adapter will wrap the Worker thread's parentPort in a stream.Duplex in order for it be used by _Network-Services_.
`ts`
const portStream = createPortStream();
#### Create a Service using the portStream instance and create a Service App using an instance of Greeter.
`ts`
const service = createService(portStream);
service.createServiceApp(new Greeter());
That's all it takes to scale this Greeter application. Please see the Hello, World! example for a complete working implementation.
#### scalability.createService(stream)
- stream An instance of a WorkerPool or an instance of a PortStream. This is a type narrowed version of the _Network-Services_ createService helper function. This helper function will accept either a WorkerPool or a PortStream as an argument, both of which are stream.Duplex.
Returns:
_public_ service.createServiceApp\
- app
Returns:
_public_ service.createServiceAPI\
- options timeout
- Optional argument in milliseconds that specifies the timeout for function calls. Default: undefined (i.e., no timeout).
Returns: A Proxy of type that consists of asynchronous analogues of methods in .
#### scalability.createWorkerPool(options)
- options workerCount
- Optional argument that specifies the number of worker threads to be spawned.workerURL
- The URL or path to the .js module file. This is the module that will be scaled according to the value specified for workerCount.restartWorkerOnError
- A boolean setting specifying if Workers should be restarted on error. Default: falseworkerOptions
- Optional worker_threads.WorkerOptions to be passed to each Worker instance.duplexOptions
- Optional stream.DuplexOptions to be passed to the stream.Duplex i.e., the parent class of the WorkerPool.
Returns:
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.
#### scalability.createPortStream(options)
- options Optional stream.DuplexOptions to be passed to the stream.Duplex i.e., the parent class of the PortStream.
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.
If you have a feature request or run into any issues, feel free to submit an issue or start a discussion. You’re also welcome to reach out directly to one of the authors.