docs/api/zone.md
zonecreate(id: string, settings: ZoneSettings = DEFAULT_SETTINGS): Zoneget(id: string): Zonecurrent: Zonenode: ZoneZoneSettings
DEFAULT_SETTINGS: ZoneSettingsZone
zone.id: stringzone.broadcast(code: string): Promise<void>zone.broadcast(function: (...args: any[]) => void, args?: any[]): Promise<void>zone.execute(moduleName: string, functionName: string, args?: any[], options?: CallOptions): Promise<Result>zone.execute(function: (...args[]) => any, args?: any[], options?: CallOptions): Promise<Result>CallOptions
Result
Zone is a key concept of napajs that exposes multi-thread capabilities in JavaScript world, which is a logical group of symmetric workers for specific tasks.
Please note that it's not the same zone concept of a context object for async calls in Dart, or Angular, or a proposal in TC39.
Zone consists of one or multiple JavaScript threads, we name each thread worker. Workers within a zone are symmetric, which means code executed on any worker from the zone should return the same result, and the internal state of every worker should be the same from a long-running point of view.
Multiple zones can co-exist in the same process, with each loading different code, bearing different states or applying different policies, like heap size, etc. The purpose of having multiple zone is to allow multiple roles for complex work, each role loads the minimum resources for its own usage.
There are two types of zone:
There are two operations, designed to reinforce the symmetry of workers within a zone:
broadcast to bootstrap the application, pre-cache objects, or change application settings. Function broadcastSync is also offered as a synchronized version of broadcast operations.Zone operations are on a basis of first-come-first-serve, while broadcast takes higher priority over execute.
It creates a Napa zone with a string id. If a zone with the id is already created, an error will be thrown. ZoneSettings can be specified for creating zones.
Example 1: Create a zone with id 'zone1', using default ZoneSettings.
var napa = require('napajs');
var zone1 = napa.zone.create('zone1');
Example 2: Create a zone with id 'zone2', with 1 worker.
var zone2 = napa.zone.create('zone2', {
workers: 1
});
It gets a reference of zone by an id. Error will be thrown if the zone doesn't exist.
Example:
var zone = napa.zone.get('zone1');
It returns a reference of the zone of the currently running isolate. If it's under node, it returns the node zone.
Example: Get current zone.
var zone = napa.zone.current;
It returns a reference to the node zone. It is equivalent to napa.zone.get('node');
Example:
var zone = napa.zone.node;
ZoneSettingsSettings for zones, which will be specified during the creation of zones. If not specified, DEFAULT_SETTINGS will be used.
Number of workers in the zone.
DEFAULT_SETTINGSDefault settings for creating zones.
{
workers: 2
}
ZoneZone is the basic concept to execute JavaScript and apply policies in Napa. You can find its definition in Introduction. Through the Zone API, developers can broadcast JavaScript code on all workers, or execute a function on one of them. When you program against a zone, it is the best practice to ensure all workers within a zone are symmetrical to each other, that is, you should not assume a worker may maintain its own states.
The two major sets of APIs are broadcast and execute, which are asynchronous operations with a few variations on their inputs.
It gets the id of the zone.
It asynchronously broadcasts a snippet of JavaScript code in a string to all workers, which returns a Promise of void. If any of the workers failed to execute the code, the promise will be rejected with an error message.
Example:
var napa = require('napajs');
var zone = napa.zone.get('zone1');
zone.broadcast('var state = 0;')
.then(() => {
console.log('broadcast succeeded.');
})
.catch((error) => {
console.log('broadcast failed.')
});
It synchronously broadcasts a snippet of JavaScript code in a string to all workers. If any of the workers failed to execute the code, an exception will be thrown with an error message.
Remarks:
broadcastSync on current zone. It will cause a deadlockExample:
var napa = require('napajs');
var zone = napa.zone.get('zone1');
try {
zone.broadcastSync('var state = 0;');
console.log('broadcast succeeded.');
} catch (error) {
console.log('broadcast failed.')
}
It asynchronously broadcasts an anonymous function with its arguments to all workers, which returns a Promise of void. If any of the workers failed to execute the code, the promise will be rejected with an error message.
Remarks:
broadcast's return valueorigin property, it will use the current file as origin, which will be used to set __filename and __dirname. (See transporting functions)Example:
zone.broadcast((state) => {
require('some-module').setModuleState(state)
}, [{field1: 1}])
.then(() => {
console.log('broadcast succeeded.');
})
.catch((error) => {
console.log('broadcast failed:', error)
});
It synchronously broadcasts an anonymous function with its arguments to all workers. If any of the workers failed to execute the code, an exception will be thrown with an error message.
Remarks:
broadcastSync on current zone. It will cause a deadlockbroadcastSync will not return until that Promise resolved or rejected.origin property, it will use the current file as origin, which will be used to set __filename and __dirname. (See transporting functions)Example:
try {
zone.broadcastSync((state) => {
require('some-module').setModuleState(state)
}, [{field1: 1}]);
console.log('broadcast succeeded.');
} catch (error) {
console.log('broadcast failed:', error)
}
Execute a function asynchronously on an arbitrary worker via module name and function name. Arguments can be of any JavaScript type that is transportable. It returns a Promise of Result. If an error happens, either bad code, user exception, or timeout is reached, the promise will be rejected.
Example: Execute function bar in module foo, with arguments [1, 'hello', { field1: 1 }]. 300ms timeout is applied.
zone.execute(
'foo',
'bar',
[1, "hello", {field1: 1}],
{ timeout: 300 })
.then((result) => {
console.log('execute succeeded:', result.value);
})
.catch((error) => {
console.log('execute failed:', error);
});
Execute a function object asynchronously on an arbitrary worker. Arguments can be of any JavaScript type that is transportable. It returns a Promise of Result. If an error happens, either bad code, user exception, or timeout is reached, promise will be rejected.
Remarks:
origin property, it will use the current file as origin, which will be used to set __filename and __dirname. (See transporting functions)Example:
zone.execute((a: number, b: string, c: object) => {
return a + b + JSON.stringify(c);
}, [1, "hello", {field1: 1}])
.then((result) => {
console.log('execute succeeded:', result.value);
})
.catch((error) => {
console.log('execute failed:', error);
});
Output:
execute succeeded: 1hello{"field1":1}
Another example demonstrates accessing __filename when executing an anonymous function:
// File: /usr/file1.js
zone.execute(() => { console.log(__filename);});
Output:
/usr/file1.js
CallOptionsInterface for options to call functions in zone.execute.
Timeout in milliseconds. Default value 0 indicates no timeout.
ResultInterface to access the return value of execute.
JavaScript value returned from the function which is invoked from zone.execute/executeSync. Napa marshalls/unmarshalls transportable values between different workers (V8 isolates). Unmarshalling will happen when the first result.value is queried.
Example:
var value = result.value;
Marshalled payload (in JSON) from the returned value. This field is for users that want to pass results through to its caller, where the unmarshalled value is not required.
Example:
var payload = result.payload;
TransportContext that is required to unmarshall result.payload into result.value.
Example:
var napa = require('napajs');
var zone = napa.zone.create('zone1');
zone.execute(() => { return 0; }, [])
.then((result) => {
// Manually marshall.
var transportContext = result.transportContext;
var value = napa.transport.unmarshall(result.payload, result.transportContext);
// result.value and manual unmarshall from payload are the same.
assert.equal(value, result.value);
});