Skip to content

WebSocket Based Changes Feed

Edvard Pitka edited this page Aug 28, 2017 · 2 revisions

Sync Gateway supports sending the _changes feed over a WebSocket connection. This is a Couchbase extension of the CouchDB replication protocol.

WebSocket mode is conceptually the same as continuous mode -- both leave the socket open and send new notifications from the server as changes occur -- but it should avoid issues with proxy servers and gateways that cause continuous mode to fail in many real-world mobile use cases. (The primary problem is buggy HTTP chunked-mode body parsing that buffers up the entire response before sending any of it on; since the continuous feed response never ends, nothing gets through to the client.)

Connecting

The client requests WebSockets by setting the _changes URL's feed query parameter to websocket, and opening a WebSocket connection to that URL:

GET /db/_changes?feed=websocket HTTP/1.1
Connection: Upgrade
Upgrade: websocket
...

(Unfortunately Apache CouchDB does not return an error on such a request, even though it doesn't support WebSockets; instead it just reverts to normal feed. This means a client must either fall back to a regular feed if the WebSocket connection attempt fails, or determine whether the server supports WebSockets before requesting the feed (probably from the Server response header, or the JSON body of GET /.)

Specifying options

After the connection opens, the client MUST send a single textual message to the server, specifying the feed options. This message is identical to the body of a regular HTTP POST to _changes, i.e. it's a JSON object whose keys are the parameters (for example, {"since": 112233, "include_docs": true}). Depending on which client you use, make sure that options are sent as binary. See https://github.com/couchbase/sync_gateway/issues/2855 for more info.

The client should not send any further messages.

Messages

Once the server receives the options, it will begin to send text-format messages. The messages are JSON; each contains one or more change notifications (in the same format as the regular feed) wrapped in an array:

[ {"seq":1022,"id":"beer_Indiana_Amber","changes":[{"rev":"1-e8f6b2e1f220fa4c8a64d65e68469842"}]},
  {"seq":1023,"id":"beer_Iowa_Pale_Ale","changes":[{"rev":"1-db962c6d93c3f1720cc7d3b6e50ac9df"}]}
]

(The current server implementation sends at most one notification per message, but this could change. Clients should accept any number.)

An empty array is a special case: it denotes that at this point the feed has finished sending the backlog of existing revisions, and will now wait until new revisions are created. It thus indicates that the client has "caught up" with the current state of the database.

The websocket mode behaves like the continuous mode: after the backlog of notifications (if any) is sent, the connection remains open and new notifications are sent as they occur.

Compressed Feed

For efficiency, the feed can be sent in compressed form; this greatly reduces the bandwidth and is highly recommended.

To signal that it accepts a compressed feed, the client adds "accept_encoding":"gzip" to the feed options in the initial message it sends.

Compressed messages are sent from the server as binary. This is of course necessary as they contain gzip data, and it also lets the client distinguish them from uncompressed messages. (The server will only ever send one kind.)

The compressed messages sent from the server constitute a single stream of gzip-compressed data. They cannot be decompressed individually! Instead, the client should open a gzip decompression session when the feed opens, and write each binary message to it as input as it arrives. The output from the decompressor consists of a sequence of JSON arrays, each of which has the same interpretation as a text message (above).

Clone this wiki locally