Updating doku
This commit is contained in:
parent
79227d5950
commit
cf5aec61c0
@ -263,6 +263,8 @@ export class NopeConnectivityManager implements INopeConnectivityManager {
|
||||
*/
|
||||
public set isMaster(value: boolean) {
|
||||
this.__isMaster = value;
|
||||
// We want to forward our new status.
|
||||
this._sendStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,7 +308,7 @@ export class NopeConnectivityManager implements INopeConnectivityManager {
|
||||
if (masters.length === 0) {
|
||||
throw Error("No Master has been found !");
|
||||
} else if (masters.length > 1) {
|
||||
throw Error("Multiple Masters has been found!");
|
||||
throw Error("Multiple Masters has been found!" + JSON.stringify(masters));
|
||||
}
|
||||
|
||||
return masters[0];
|
||||
@ -375,6 +377,7 @@ export class NopeConnectivityManager implements INopeConnectivityManager {
|
||||
}
|
||||
|
||||
await this.emitBonjour();
|
||||
await this._sendStatus();
|
||||
|
||||
this.ready.setContent(true);
|
||||
}
|
||||
@ -473,7 +476,10 @@ export class NopeConnectivityManager implements INopeConnectivityManager {
|
||||
* @memberof NopeConnectivityManager
|
||||
*/
|
||||
protected _sendStatus(): void {
|
||||
this._communicator.emit("StatusChanged", this.info);
|
||||
// Test if we are connected
|
||||
if (this._communicator.connected.getContent()) {
|
||||
this._communicator.emit("StatusChanged", this.info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,30 +25,9 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "SyntaxError",
|
||||
"evalue": "Identifier 'nope' has already been declared",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"evalmachine.<anonymous>:1",
|
||||
"// First lets install nope using npm",
|
||||
"^",
|
||||
"",
|
||||
"SyntaxError: Identifier 'nope' has already been declared",
|
||||
" at Script.runInThisContext (node:vm:129:12)",
|
||||
" at Object.runInThisContext (node:vm:305:38)",
|
||||
" at run ([eval]:1054:15)",
|
||||
" at onRunRequest ([eval]:888:18)",
|
||||
" at onMessage ([eval]:848:13)",
|
||||
" at process.emit (node:events:390:28)",
|
||||
" at emit (node:internal/child_process:915:12)",
|
||||
" at processTicksAndRejections (node:internal/process/task_queues:84:21)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// First lets install nope using npm\n",
|
||||
"const nope = require(\"../dist-nodejs/index.nodejs\")\n",
|
||||
@ -88,6 +67,10 @@
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### `getDispatcher`-function:\n",
|
||||
"The `getDispatcher`- function automatically trys to return the dispatcher as `Singleton`. This means, that their will be exactly ***1*** dispatcher in a process. To receive a second dispatcher-instance (which is for performance reasons not recommend) in your process you must set the ``singleton``-flag to `false`\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Settings for creating:\n",
|
||||
"\n",
|
||||
"The relevant Settings are described by the `INopeDispatcherOptions`. This options allows to define:\n",
|
||||
|
238
wiki/13-ConnectivityManager.ipynb
Normal file
238
wiki/13-ConnectivityManager.ipynb
Normal file
@ -0,0 +1,238 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# NoPE - Connectivity Manager\n",
|
||||
"\n",
|
||||
"The NoPE-Dispatcher uses one `ConnectivityManager`. The manager observes the connection and remotly connected dispatchers (and their `ConnectivityManager`). The Manager detects newly connected dispatchers and disconnected dispatchers. Additionally, it sends a StatusMessage (in the form of `INopeStatusInfo`). This status message is interpreted as heartbeat. The `ConnectivityManager` checks those heartbeats with a defined interval. If a specific amount of time is ellapsed, the remote dispatcher is marked as `slow` -> `warning` -> `dead`. After an additional delay in the state `dead` the dispatcher is altough removed.\n",
|
||||
"\n",
|
||||
"## Master\n",
|
||||
"\n",
|
||||
"Defaultly a `ConnectivityManager` is elected as `master`. The master is defined as the `ConnectivityManager` with the highest `upTime`. \n",
|
||||
"\n",
|
||||
"> Alternativly a master can be forced.\n",
|
||||
"\n",
|
||||
"## Synchronizing time\n",
|
||||
"\n",
|
||||
"Because we asume, that **NoPE** is running on different computing nodes, we have to be able to synchronize the time between those elements. Therefore the `ConnectivityManager` is able to sync the time (by providing a `timestamp` and an additional `delay` that was needed to get to the call (for instance `ping / 2`))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// First lets install nope using npm\n",
|
||||
"const nope = require(\"../dist-nodejs/index.nodejs\")\n",
|
||||
"\n",
|
||||
"// Create a communicator:\n",
|
||||
"// We will use the event layer (which just runs internally)\n",
|
||||
"const communicator = nope.getLayer(\"event\");\n",
|
||||
"\n",
|
||||
"// Lets create our dispatcher\n",
|
||||
"\n",
|
||||
"// 1. Dispatcher simulates our local system\n",
|
||||
"const localDispatcher = nope.dispatcher.getDispatcher({\n",
|
||||
" communicator,\n",
|
||||
" id: \"local\"\n",
|
||||
"}, null, false);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"> For Jupyter we need an extra async wrapper to wait for initalizing the dispatcher:\n",
|
||||
"\n",
|
||||
"see here for the details in Jupyter: https://n-riesco.github.io/ijavascript/doc/async.ipynb.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"$$.async();\n",
|
||||
"// Lets wait for our element to be ready.\n",
|
||||
"localDispatcher.ready.waitFor().then($$.done);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we want to listen to newly connected dispatchers. For this purpose, we create an observer, which will listen to changes."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// Subscribe to changes\n",
|
||||
"const observer = localDispatcher.connectivityManager.dispatchers.onChange.subscribe(data => {\n",
|
||||
" // Log the changes\n",
|
||||
" console.log(\"onChange - listener\");\n",
|
||||
" console.log(\"-------------------\");\n",
|
||||
" console.log(\"added =\", data.added);\n",
|
||||
" console.log(\"removed =\", data.removed);\n",
|
||||
"});"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Additionally we want to show the currently connected dispatchers. In this data the own dispatcher will **allways** be included:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// Show our connected Dispatchers\n",
|
||||
"let connectedDispatchers = localDispatcher.connectivityManager.dispatchers.data.getContent();\n",
|
||||
"let localDispatcherIncluded = connectedDispatchers.includes(localDispatcher.id);\n",
|
||||
"\n",
|
||||
"// Now lets log our results.\n",
|
||||
"console.log(\"connectedDispatchers =\", connectedDispatchers);\n",
|
||||
"console.log(\"localDispatcherIncluded =\", localDispatcherIncluded);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now that we have implemented our listeners and have seen the connected dispatchers (which is only the `\"local\"`-dispatchre), We will add an additional dispatcher. This should result in calling our `onChange`-listener. Additionally, we wait until our `remoteDispatcher` is initalized"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// 2. Dispatcher simulates our remote system\n",
|
||||
"const remoteDispatcher = nope.dispatcher.getDispatcher({\n",
|
||||
" communicator,\n",
|
||||
" id: \"remote\"\n",
|
||||
"}, null, false);\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we want to see, which system is the current master. This should be our `local`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// We expect to be the master, because the localDispatcher has been created first.\n",
|
||||
"console.log(\"master =\", localDispatcher.connectivityManager.master.id);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can now force the remote dispatcher to be our master, by setting the master. (For this purpose we can later use a base service ==> then we just have to call the service) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"$$.async();\n",
|
||||
"\n",
|
||||
"remoteDispatcher.connectivityManager.isMaster = true;\n",
|
||||
"localDispatcher.connectivityManager.isMaster = false;\n",
|
||||
"\n",
|
||||
"// Our messaging is async ==> we wait an amount of time\n",
|
||||
"setTimeout($$.done,1000)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// We expect the master to be the remote.\n",
|
||||
"console.log(\"master =\", localDispatcher.connectivityManager.master.id);\n",
|
||||
"console.log(\"master-info =\", localDispatcher.connectivityManager.master);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now lets see what happens if we adapt the heartbeat intervall of our *local* instance. We want to receive every 50 ms a heartbeat:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"$$.async()\n",
|
||||
"\n",
|
||||
"localDispatcher.connectivityManager.setTimings({\n",
|
||||
" // our system will send every 50 ms an heartbeat.\n",
|
||||
" sendAliveInterval: 500,\n",
|
||||
" // we will check that after\n",
|
||||
" checkInterval: 25,\n",
|
||||
" // will mark dispatchers as slow after not receiving heartbeats for 50ms\n",
|
||||
" slow: 50,\n",
|
||||
" // we will mark dispatchers with a warning flag after 50 ms\n",
|
||||
" warn: 100,\n",
|
||||
" // we mark it as dead after 0.5 s\n",
|
||||
" dead: 500,\n",
|
||||
" // We will remove the dispatcher after 1 s\n",
|
||||
" remove: 1000,\n",
|
||||
"});\n",
|
||||
"\n",
|
||||
"const renderStatus = () => {\n",
|
||||
" console.log(\"master-info =\", localDispatcher.connectivityManager.master.status)\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"setTimeout(renderStatus, 75);\n",
|
||||
"setTimeout(renderStatus, 250);\n",
|
||||
"setTimeout(renderStatus, 750);\n",
|
||||
"\n",
|
||||
"// We reset the timeouts.\n",
|
||||
"setTimeout(() => localDispatcher.connectivityManager.setTimings({}), 1200);\n",
|
||||
"setTimeout(() => $$.done(), 2000);\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "JavaScript (Node.js)",
|
||||
"language": "javascript",
|
||||
"name": "javascript"
|
||||
},
|
||||
"language_info": {
|
||||
"file_extension": ".js",
|
||||
"mimetype": "application/javascript",
|
||||
"name": "javascript",
|
||||
"version": "17.3.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
Loading…
Reference in New Issue
Block a user