Skip to content

Message Counter system

Dan Sheppard edited this page Jul 10, 2019 · 1 revision

The web assembly uses message counters to avoid infinite loops of data between the react and the web assembly. There is subtlety in their use, but used correctly they should be robust to the protocol becoming more complex over time without further elaboration of cases.

The "message-counter" key is included with some messages. This is a strictly increasing integer. Not all messages include a message counter.

After the react has responded to everything contained in the message stream preceding a counter value and created any necessary responses back to the web assembly then it should send the message counter back. Sending this value back confirms that the react is now happy with the state having fully processed everything up to that point.

For example, say react receives a message with some position and counter 28. It then reacts to this by, for example, updating all of its internal state and sending any necessary messages back to the web assembly. Only after this is all done and the react is satisfied it is in a quiescent state with respect to the messages it has received upto that point then it should send the counter back, meaning "ok that's all of the messages up to the counter value X one reacted to".

The reason for this system is to avoid the react instructing the webassembly based on out of date information from delayed events or ongoing, unreported actions. The webassembly sends these counter values out at important points along its time line and, by receiving them, knows it can execute the given events after those events have been taken into consideration.

For example, consider the browser being moved slowly with a mouse from 1,000,000 to 1,000,100 to 1,000,200, etc, the button maybe even being up-and-downed every short distance to legitimately demand URL updates. This generates a stream of position events to the react. In busy times the react could be processing one event while not knowing that another is underway. Say it's received 1,000,000 and decides to reflect it back to the browser. In the meantime the browser is already close to 1,000,100 when it receives "position 1,000,000". Does it backtrack? We hope not. Alternatively, two such messages could be "in flight" at once creating a flip-flopping as each is reflected to the other.

By including a message counter after an update the webassembly can easily detect that an event is based on stale information and store up the events in a queue. When the react eventually receives the correct, current information it will send other events to update the webassembly, and also send the current message counter number. At this point the webassembly knows that the events in its queue are after consideration of all events it has sent and releases them all.

The messages are queued rather than dropped to allow for deltas (see following example):

Consider the following sequence.

  • wasm at location 1,000,000. Sends to react with message-counter 42.
  • wasm at location 1,100,000. Sends to react with message-counter 43.
  • react sees "1,000,000 and counter=42" and duly reflects back "position 1,000,000 and counter=42" to the wasm.
  • react notices some button press in its own domain which means "zoom in 10%" and sends "zoom in 10% and counter=42" to the wasm.
  • wasm sees "position 1,000,000" and "zoom in 10%" messages and queues them because it's currently at 43.
  • react sees "1,100,000 and counter=43", and also another "zoom in 10%", and duly reflects back "position 1,100,000 and zoom in 10% and counter=43" to the wasm.
  • wasm notices that the counter is current and unqueues "position 1,000,000" then "zoom in 10%" then from the current message "position 1,100,000" and "zoom in 10%". The result is the browser is at position 1,100,000 (still) and has been zoomed in 20%.

Note that if the messages when counter was 42 were discarded we'd not have zommed in enough.

The only important consideration for the react is to only send the counter when it is sure that it has fully reacted and replied back to the wasm with all consequences of all messages up to that point.

This protocol is based on the notion of Lamport Time for which there is a good wikipedia page