XIBLEDOCS

State must be transfered between nodes to keep track of data specific to certain events. Within XIBLE, state primarely exists to track values related to "event" nodes. An instance of the FlowState class is provided to each event on a Node. In most cases it is required that this state is passed on to other function calls on the node itself, its inputs and outputs.

Managing state

Let' take a look at a fictional "event" node with two outputs;

  • trigger
  • value

The purpose of this node is to simply return the value associated to an event called "somevent" which triggered the "trigger" output. For demonstration purposes, we will hook up this node to a "console.log" node. Trigger output to trigger input, value output to value input.

Incorrectly passing values

If the fictional "event" node would simply store the value of the event in a local variable and return that variable when requested on the "value" output, a race condition may occur. If a new event is triggered while "console.log" is fetching the value related to the event, the newer value is wrongly returned to "console.log".

The following code snippet demonstrates this undesired behaviour;

// this is an example of how _NOT_ to manage state.// do not replicate this.module.exports = (NODE) => {  // stores the value when someevent is raised  let value;  // respond to the value output  NODE.getOutputByName('someoutput')  .on('trigger', async (conn, state) => {    return value;  });  // setup the event handler  NODE.on('trigger', (state) => {    someEventHandler.on('someevent', (event) => {      // save the value to its variable      value = event.value;      // trigger the 'trigger' output      NODE.getOutputByName('trigger')      .trigger(state);    });  });});

Using state to store your values

To solve this, store your values in the state object that is passed between nodes. The below example does produce the result you would expect;

module.exports = (NODE) => {  // respond to the value output  NODE.getOutputByName('someoutput')  .on('trigger', async (conn, state) => {    const thisState = state.get(NODE);    return thisState.value;  });  // setup the event handler  NODE.on('trigger', (state) => {    someEventHandler.on('someevent', (event) => {      // save a value to the state chain      state.set(NODE, {value: event.value});      // trigger the 'trigger' output      NODE.getOutputByName('trigger')      .trigger(state);    });  });});

If a certain value is idempotent, you can resort to simply storing the value in a local variable. Keep in mind that for "event" nodes this is hardly ever the case.

Implementation examples