The vmblu runtime
■ Overview
The vmblu runtime is a small library whose function is
- to instantiate the nodes that make up the running application,
- to switch messages between the nodes of an application,
- to implement a promise-based mechanism for request/reply messages.
The runtime is part of the vmblu repo and can be consulted there to learn the details of its implementation.
The overhead of the runtime is limited and message switching is very efficient.
■ Scaffold - creating the nodes
The runtime scaffold function is invoked at the end of every model-name.app.js function.
Remember that a vmblu application is just a list of nodes with connections between them. For each node scaffold invokes the factory function of the node that creates the actual node.
The node-creation function will use the parameters specified in rx to modify the creation characteristics of the node (eg where the node is created, its debugging characteristics etc.)
The runtime passes two structures to the factory function, tx, or the transmitter, and sx, the settings. The settings are completely up to the node and not used by the runtime. The tx object contains the functions that allow a node to transmit messages.
The content of that node is opaque to the runtime, all that the factory function needs to return is an object that contains the handlers for the node.
If the complete node is returned that is ok of course, but there are situations possible where a node is not available under susch a 'closed' form and then an object can be returned that just contains the handlers for the node.
The scaffold function will then extract the handlers and link the handlers to the input pins of the node.
For each output pin of a node scaffold makes a table with the nodes + pins that are connected to that pin.
So, in principle, whenever a node sends a message on an output pin tx.send(messageName, payload), the runtime can get the list of input pins connected to that output pin and call the handler for each of these input pins with the payload as parameter.
■ Switching messages
However, when a node sends a message, the handlers for that message are not called immediately, instead the message is added to a message queue to make sure that all nodes get equal access to processing time.
The way this works is simple: there are two message queues, the incoming queue and the outgoing queue. At any given moment the runtime handles the incoming queue and calls the required handler for each message on the incoming queue. When a message is sent during that process, it is put on the outgoing queue.
When the runtime has handled all message on the incoming queue, it switches both queus and the outgoing queue becomes the incoming queue and the message handling can start again.
When there are no more messages the runtime will be called periodically to see if there are new messages and also has a built-in back-off algorithm to minimise actual processor time.
■ Request/Reply mechanism
When a pin is marked as a request pin, that means that it can send a request and wait for the answer of the node(s) connected to that node.
In order to make this work, each message has a unique identifier, a simple counter actually, and the runtime creates a promise that is stored in a map structure together with the identifier. When a connected node then sends a reply associated with the request - the reply contains the original identifier - then the runtime can look up the promise and resolve the promise with the returned payload as its parameter.