micro-toolkit/event-bus-zeromq

View on GitHub
RFC.md

Summary

Maintainability
Test Coverage
---
domain: micro-toolkit
name: Event BUS Protocol
editor: Pedro Januário <prnjanuario@gmail.com>
---

The Event BUS Protocol defines mechanisms for sharing events across a set of clients. It allows clients to work with subtrees of the event topics, trigger events. It is originated from the awesome work of the ØMQ Community and is based on Clustered Hashmap Protocol and in the Clone pattern defined in Chapter 5 of the ØMQ Guide.

The protocol flows are quite similar, some functionality were dropped and others added, the serialization format and commands are also slightly different.

**NOTE:** The format and description of the protocol is also "borrowed" from the ØMQ community and from Pieter Hintjens protocols and documentation.

## Language

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED",  "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 (see "[Key words for use in RFCs to Indicate Requirement Levels](http://tools.ietf.org/html/rfc2119)").

## Goals

This protocol is meant to provide a basis for reliable pub-sub across a cluster of clients connected over a 0MQ network. It defines a abstraction consisting of key-value pairs, where the key is topic the event is published. Any client can trigger a new key-value pair at any time, and it will be propagated to all interested clients. A client can join the network at any time.

## Architecture

It connects a set of client applications and a set of servers. Clients connect to the server. Clients do not see each other. Clients can come and go arbitrarily.

The Event BUS is referenced as the server, where client applications can both consume and/or produce events.

### Ports and Connections

The server MUST open three ports as follows:

* A SNAPSHOT port (0MQ ROUTER socket) at port number P.
* A PUBLISHER port (0MQ PUB socket) at port number P + 1.
* A COLLECTOR port (0MQ ROUTER socket) at port number P + 2.

The client SHOULD open at least two connections:

* A SNAPSHOT connection (0MQ DEALER socket) to port number P.
* A SUBSCRIBER connection (0MQ SUB socket) to port number P + 1.

The client MAY open a third connection, if it wants to produce events:

* A PUBLISHER connection (0MQ DEALER socket) to port number P + 2.

From the ØMQ Reference Manual

> When receiving messages a ROUTER socket shall prepend a message part containing the identity of the originating peer to the message before passing it to the application. When sending messages a ROUTER socket shall remove the first part of the message and use it to determine the identity of the peer the message shall be routed to.

This extra frame is not shown in the commands explained below.

### State Synchronization

The client MUST start by sending a SYNCSTART command to its snapshot connection. This command consists of two frames as follows:

```
SYNCSTART command
-----------------------------------
Frame 0: "SYNCSTART", as 0MQ string
Frame 1: subtree/s specification, as 0MQ string
Frame 2: sequence specification, 8 bytes in network order
```

The subtree specification MAY be empty. If not empty, it consists of a slash followed by one or more path segments, ending in a slash. Eg: '/topic/'. The client MAY request sync for several subtrees using ';' so separated them. Eg: '/topic/;/othertopic/'.

The sequence specification MAY be 0. If not empty it will consist in natural number that will be used to filter events present in the snapshot. It will return all events with sequence number above.

The server MUST respond to a SYNCSTART command by sending zero or more SYNC commands to its snapshot port, followed with a SYNCEND command.

Due to the implementation of the ROUTER<->DEALER communication on 0MQ. The server MUST prefix each command with the identity of the client, as provided by 0MQ with the SYNCSTART command. The SYNC command specifies a single event as follows:

```
SYNC command
-----------------------------------
Frame 0: "SYNC", as 0MQ string
Frame 1: event topic, as 0MQ string
Frame 2: sequence number, 8 bytes in network order
Frame 3: event producer unique id, as 0MQ string
Frame 4: event producer timestamp, as 0MQ string in ISO-8601 format
Frame 5: event UUID, as 0MQ string formatted in v4 as specified at rfc4122
Frame 6: event data, as blob generated by Message Pack serialization
```

The SYNCEND command takes this form:

```
SYNCEND command
-----------------------------------
Frame 0: "SYNCEND"
Frame 1: subtree/s specification
Frame 2: sequence number, 8 bytes in network order
```

The sequence number MUST be the highest sequence number of the SYNC commands previously sent.

When the client has received a SYNCEND command it SHOULD start to receive messages from its subscriber connection, and apply them.

### Server-to-Client Updates

When the server has an event it MUST broadcast this on its publisher socket as a BROADCAST command. The BROADCAST command has this form:

```
BROADCAST command
-----------------------------------
Frame 0: event topic, as 0MQ string
Frame 1: sequence number, 8 bytes in network order
Frame 2: event producer unique id, as 0MQ string
Frame 3: event producer timestamp, as 0MQ string in ISO-8601 format
Frame 4: event UUID, as 0MQ string formatted in v4 as specified at rfc4122
Frame 5: event data, as blob generated by Message Pack serialization
```

The sequence number MUST be strictly incremental. The client MUST discard any BROADCAST commands whose sequence numbers are not strictly greater than the last SYNCEND or BROADCAST command received.

### Client-to-Server Updates

When the client has a new event, it MAY send this to the server via its publisher connection as a PUB command. The PUB command has this form:

```
PUB command
-----------------------------------
Frame 0: event topic, as 0MQ string
Frame 1: sequence number, 8 bytes in network order
Frame 2: event producer unique id, as 0MQ string
Frame 3: event producer timestamp, as 0MQ string in ISO-8601 format
Frame 4: event UUID, as 0MQ string formatted in v4 as specified at rfc4122
Frame 5: event data, as blob generated by Message Pack serialization
```
**** NOTES TO add related to sequence number

The UUID SHOULD be a universally unique identifier, if a reliable server architecture is used. The producer unique id, SHOULD identify the event producer.

### Reliability

This may be used in a dual-server configuration where a backup server takes over if the primary server fails. It does not specify the mechanisms used for this failover but the Binary Star pattern from the ØMQ Guide may be helpful.

To assist server reliability, the client MAY:

* Detect the lack of server heartbeats over time time period and use this as an indicator that the current server has failed.
* Connect to a backup server and re-request a state synchronization.

### Scalability and Performance

It is designed to be scalable to large numbers (thousands) of clients, limited only by system resources on the BUS. Since all updates pass through a single process the overall throughput will be limited to some millions of updates per second, at peak, and probably less.

### Security

It does not implement any authentication, access control, or encryption mechanisms and should not be used in any deployment where these are required.

### Reference Implementations

The C99 Clone examples from Chapter 5 of the Guide (see "[ØMQ - The Guide](http://zguide.ØMQ.org)") act as the prime reference implementation for it.