Real-Time with Flowdock


Published on

Ville Lautanala describes different transport channels that allow pushing data from servers to clients in real time.

He also introduces a case study of Flowdock's experience with and WebSockets.

Presentation from Frontend Finland meetup, March 14th. A slightly modified version was presented at SFJS, April 3rd.

Published in: Technology
1 Like
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Real-Time with Flowdock

  1. 1. Real-Time withI’m going to talk about the most prominent aspect in our single page app.
  2. 2. @lautisWear funny hats and have a messy desk at Flowdock. Occasionally write code. Spend muchtime in backend these days.
  3. 3. “There’s no time like real-time”Real-time is necessary for a chat app. Interval polling wouldn’t work.Big part of our app, no Backbone etc.
  4. 4. Demo
  5. 5. Stream changes from backend And send messages* stream and apply changes* send some messages to server=> To achieve this, some kind of transport channel between server and client is necessary.
  6. 6. Long-polling XHR-streaming HTMLFile Server-Sent Events WebSocket JSONP streaming XHR multipartEach have their shortcomings, work on different browsers, and some work cross-domain,others not.
  7. 7. 3 implementations with 7 transportsWe couldn’t really decide what to use. There isn’t really a one-size fits all option, but youdefinitely could do with less.
  8. 8. Long-polling HTTP/1.1 200 OK Content-Type: application/json; [{content: json}]The most obvious choice, works on every browser. Wait until you have something to tell toclient. Rinse, repeat.
  9. 9. XHR-streaming HTTP/1.1 200 OK {content: json} {content: json} {content: json}Streaming: multiple chunks in one response. Widely used, not much advertised.XHR-streaming works by parsing the response after each onReadyStateChange.ResponseText will be huge if your HTTP request runs for long time, so periodic reconnectionis needed. Flowdock uses 60 seconds, requests have payload about user activity.
  10. 10. Server-Sent Events HTTP/1.1 200 OK Content-Type: text/event-stream data: {content: json} id: 2 Sent to server on reconnect data: {content: json}SSE aka ES is standardization of XHR streaming pattern. ID attribute allows seamlessreconnections from client point-of-view.Hopefully will be in FD mobile soon.
  11. 11. In JavaScript var es = new EventSource(/events); es.onmessage = function (e) { console.log(JSON.parse(; };There’s actually something worth showing. Simple, bind message event listener.Other events too
  12. 12. Built-in in modern browsersGood news: Chrome, Safari 5, FF6, Opera 11
  13. 13. No IEEven IE10 seems unlikely
  14. 14. No AndroidUnlike iOS, Andriod doesn’t have ES. Even Android 4.0 is missing this. Maybe Chrome forAndroid will fix this.
  15. 15. Use shim instead SSE are “just” HTTP, you can implement it in JavaScript, today. And many have doneit. Use some available shim.
  16. 16. Streams are unidirectionalXHR requests are needed to post data
  17. 17. Sockets are bidirectionalSome kind of socket interface would be nice. Luckily for us, WebSockets are part of HTML5.
  18. 18. WebSockets var socket = new WebSocket(/socket); socket.onmessage = function (e) { console.log(JSON.parse(; }; socket.onopen = function() { var m = {content: json}; socket.send(JSON.stringify(m)); }I’m not going to exaplain the WebSocket protocol here, the standardized version is a bit morecomplicated than what we saw previously. The JavaScript API is more interesting.Receiving messages with websockets is pretty similar to EventSource. Sending messages istrivial as long as you have received onopen.
  19. 19. Caveats • Limited browser support • Proxy problems • Safari crashes when used with Proxy Auto-ConfigurationSafari has different protocol than others, IE 10 will be the first IE to support WS. NO SHIMSWebSockets require full HTTP 1.1.No way to detect if user has PAC. Rare.
  20. 20. Socket.IO “Its care-free realtime 100% in JavaScript.”Abstraction layer on top of different transports. NO SSE. Server-side and client-side.We’ve been rolling Socket.IO out slowly for last month or so (bugs!).
  21. 21. Bugs • Reconnection race-conditions • Infinite loops with XHR-polling • DOM Exception 11*Socket.IO didn’t know that there already was a reconnection attempt on going andestablished multiple connections.* XHR-polling transport client could get in state where it didn’t handshake properly but onlyhammered the XHR-polling endpoint.* INVALID_STATE_ERR, send data with unopened websocket. Yet another race-condition.
  22. 22. Socket.IO“Its care-free realtime 100% in JavaScript.”
  23. 23. Why bother?If it’s so horrible, why even bother?
  24. 24. Science! It Works, Bitches.Let’s look at the numbers.
  25. 25. Latency mattersWe knew websockets would be fastest, but by how much?Benchmark by sending a message and test how long it took to receive it
  26. 26. 300 225 150 75 0 Ping XHR-streaming WebSocket Round-trip latencyBaseline: ping to our servers in Germany was 52msXHR: 240ms. TCP and especially SSL handshake is expensive. Streaming part doesn’t addmuch penalty.WebSockets came pretty close to ping, about 61ms. Node proxy in test setup + our backendserver added latency.
  27. 27. Real-world metrics from FlowdockHow many can use websockets? Clients as guinea pigs.
  28. 28. 96% use WebSockets No Flash fallbackOver 80% have up-to-date Webkit based browsers.
  29. 29. 3% have obsolete browsersIE users are minority.
  30. 30. 1% have network issues (or have disabled WebSockets)We don’t really know.
  31. 31. Network still sucksCan’t just wait for reply even with websockets.Network latencies vary, we have clients all around the world.
  32. 32. Render optimisticallyYou have two basic choices, either use loading indicator or render users changesoptimistically. Needless to say, we try to be on the optimistic end of the road.
  33. 33. Basic operations in Flowdock 1.Post new stuff 2.Receive new stuff 3.Modify existing stuffPost new stuff: send messagesReceive: simple, just append to the stream. unless conflictsModify: mostly tag edits, but can also be message deletion. Highlights and unread handlingare tags.
  34. 34. Posting messages • Clients process messages as much as possible • Server adds unique ID and timestamp to data • Message echoed to clientClient processes messages. In our case, this basically means that tags are parsed andmessage rendered to DOM. Later, if necessary, these changes can be reverted.Server adds some information to messages, which is needed to add new tags. Client uses thisinformation to complete the message.Last, message is echoed to all clients, including sender. This causes duplication, but data isneeded to “complete” outgoing messages.
  35. 35. Order sync SUP LOL BAR FOO FOO"Undo" pending operationsApply operation from networkRe-apply pending opsA bit like git rebase, but cheat a little
  36. 36. Modifying stuff• Add/remove tag to message• Mark message as deleted
  37. 37. Idempotent changes "Operation, which can be applied multiple times without changing the result beyond the initial application."Tags are good fit for this. You can add the same tag to a message multiple times. This isused as our event-stream contains messages the client has sent.
  38. 38. Error handling is trickyHandling errors becomes quickly quite tricky. Good MVC would make it easier, but also it’snot easy to know when some operation has failed because of poor network with WebSocketsand Socket.IO.UX implications!
  39. 39. Protips • Socket.IO will bite you • SSE is safe choice for streaming • Design for broken internetPeople put laptop to sleep, live with it. Important for single page apps. Avoid reloading.
  40. 40. Thanks!