Americastestkitchen/metricution — pull request #2 by nixpulvis (2014-05-13 03:52:00+00:00)
Title: Websockets + Redis

This is the full event driven model. I'll go over the connections that the app makes now, and why it's needed.

### Spark Cloud SSE

First thing in the chain of events is the Spark Core pushing an event to the Spark Cloud. This event is a simple name value pair.

```
"door" : STATE where STATE is one of "opened" OR "closed"
```

The Spark Cloud passes these SSEs along to our application via `https://api.spark.io/v1/events/door'`.

### rake monitor_bathrooms

This rake task runs in the background potentially on it's own server. It subscribes to the Spark Cloud SSEs. On each event it does two things.

1. It updates the associated bathroom record in the database with it's new state.
2. It publishes a redid event with the serialization of the bathroom to the channel `bathroom`.

The serialized data sent over the redid event is of the exact same form rendered by Rails for the rest of the applications JSON APIs. This allows it to be served directly from the controller.

### events#bathrooms

This controller action is in charge of serving up a web socket connection with the client. It does so utilizing Rack's hijack interface.

When the client connects to the server at `api/v1/events/bathrooms` we hijack the connection from Rails's normal flow, and serve instead a persistent websocket to the client. At the same time we also spawn a thread to listen for redis events on the `bathroom` channel. When a message is received over the channel it's passes directly to the websocket. No additional processing is needed since the event's data was sent in the proper form for Ember.

### Ember

Ember currently opens a websocket in the `BathroomsController`.

```coffeescript
url = 'ws://' + window.location.host + '/api/v1/events/bathrooms'
socket = new WebSocket(url)
socket.onmessage = (event) =>
@store.pushPayload('bathroom', JSON.parse(event.data))
```

This is the complete implementation for updating from a websocket. Due to the way `pushPayload` works this will automatically handle responses containing multiple or singular bathrooms. It will append new entries if they don't exist already, and it will update existent entries.

### Holy Shit

So yea the complexity here is pretty high, but it's truly event driven at every stage of the data flow. So that's pretty awesome.

:smiley: