-
Notifications
You must be signed in to change notification settings - Fork 339
Introduction
Following concepts are essential to understand how Napa.js works.
In Napa.js, all works related to multi-threading are around the concept of Zone, which is the basic unit to define policies and execute JavaScript code. A process may contain multiple zones, each consists of multiple JavaScript Workers.
Within a zone, all workers are symmetrical: they load the same code, serve broadcast
and execute
requests in an indistinguishable manner. Basically, you cannot ask a zone to execute code on a specific worker.
Workers across different zones are asymmetrical: they may load different code, or load the same code but reinforce different policies, like heap size, security settings, etc. Applications may need multiple zones for work loads of different purposes or different policies.
There are 2 types of zone:
- Napa zone - zone consists of Napa.js managed JavaScript workers (V8 isolates). Can be multiple, each may contain multiple workers. Workers in Napa zone support partial Node.JS APIs.
- Node zone - a 'virtual' zone which exposes Node.js eventloop, has access to full Node.js capabilities.
This complex enables you to use Napa zone for heavy-lifting work, and Node zone for IO. Node zone also compensates Napa zone on its incomplete support of Node APIs.
V8 is not designed for running JavaScript across multiple isolates, which means every isolate manages their own heap. Passing values from one isolate to another has to be marshalled/unmarshalled. The size of payload and complexity of object will greatly impact communication efficiency. In Napa, we try to work out a design pattern for efficient object sharing, based on the fact that all JavaScript isolates (exposed as workers) reside in the same process, and native objects can be wrapped and exposed as JavaScripts objects.
Following concepts are introduced to implement this pattern:
Transportable types are JavaScript types that can be passed or shared transparently across workers. They are used as value types for passing arguments in broadcast
and execute
, as well as sharing objects in key/value pairs via set
and get
.
Transportable types are:
- JavaScript primitive types: null, boolean, number, string
- Object (TypeScript class) that implement
Transportable
interface - Array or plain JavaScript object that is composite pattern of above.
- Single JavaScript value undefined
Store API is introduced as a necessary complement of sharing transportable
types across JavaScript workers, on top of passing objects via arguments. During store.set
, values marshalled into JSON and stored in process heap, so all threads can access it, and unmarshalled while users retrieve them via store.get
.
Though very convenient, it's not recommended to use store to pass values within a transaction or request, since its overhead is more than passing objects by arguments (there are extra locking, etc.). Besides, developers have the obligation to delete the key after usage, while it's automatically managed by reference counting in passing arguments.