Hacker News new | past | comments | ask | show | jobs | submit login
RESTful Realtime (realcrowd.com)
51 points by jconley on Jan 9, 2014 | hide | past | favorite | 25 comments

Screw long polling. Use websockets.

That's basically what I was going to say. I've developed a realtime system for my company that uses a REST API on the backend, but we use websockets to push updates to the clients in realtime. It's so much faster (no polling and no overhead of establishing new connections). When there's an update we hit the API once to fetch the new data and then push it out to all clients subscribed to the given data set which massively reduces load on the server.

In this approach we aren't re-establishing connections every time since the server side supports keep-alive and the clients are web browsers, which also support keep-alive.

We also hit the API once to push out changes to the subscribed clients through the connection proxy. And the next poll has relatively minimal overhead (obviously not as small as 0) to be queued back up.

In the end, though, this obviously isn't an implementation aimed at extreme efficiency. If that were the goal we'd take a much different approach.

It is about simplicity and semantic elegance.

That's an interesting approach, but it's still pooling, although I wouldn't know better.

Does anyone know what the alternatives are? Can you avoid pooling and still speak HTTP?

Yes, it's definitely still polling. It is polling about once per minute. However, at least it's only polling at the application protocol level, not the connection level. Browsers and the GRIP proxy support keep-alive so the same TCP connection is very likely to be re-used for quite a while.

HTTP by nature is request/response. To speak pure HTTP, there isn't a way around polling that I know of. Avoiding polling means implementing your own protocol over HTTP, or using WebSockets (see Comet or implementations in Socket.IO, Firebase, SignalR, etc).

There is actually a way to do streaming over HTTP without doing WebSockets. It's called "Server Sent Events" and is implemented in the EventSource API in Chrome, Firefox and Safari.

It's quite easy to fall back to long polling in older browsers and it's a very simple and straight forward format.

Yes you can certainly stream and do message passing within HTTP (for some browsers) but you can't, for instance, return headers more than once without your own application protocol.

The most interesting bit about this architecture for me is the 1:1 mapping with a pure HTTP resource. It's a bit like an implicit subscription to a pub-sub enabled resource. In this implementation we are simply calling our API like we normally would (except on the stream domain) and waiting for an update.

Or make life real simple and just use Socket.io

Will people stop writing crap "on" HTTP please and use TCP like you're supposed too! :)

Websockets is a great transport protocol for bi-direction realtime persistent connections. And it's very easy to write your own application protocol or just use WAMP from http://wamp.ws.

There's nothing wrong with using HTTP if it's done in a sensible way.

In the early days of the realtime web, long-polling was used mostly as an underlying hack in the emulation of streams. However, RealCrowd's API isn't a hack. When clients make requests to the server, they are attempting to synchronize a resource. One could argue that this kind of interface is semantically closer to what the client is trying to accomplish than one based around pure message passing.

Yes there are real problems with HTTP. There is a lot of overhead in building a connection and maintaining. It's designed to be a transient, request/response oriented protocol. Things like XmlHttpResponse are a hack and misuse.

I'm not just being pedantic about it either. Just compare server performance of RPC over Websocket to RPC over HTTP at scale.

You can do HTTP streaming, where clients access a resource of indefinite length. This should work well enough with native clients and even some modern browsers (with EventSource aka Server Sent Events, or streaming XmlHttpRequest).

Long-polling with retries is not so bad though. Even with WebSockets you'd still want a periodic heartbeat. It's all the same amount of traffic really.

One approach is to register a callback essentially. The client asks the server to send updates or notifications to a URL. Then the server sends updates to that URL. The client would need to have its own server though so it might not be viable in all situations.

As far as a REST API supporting etags and if-none-match headers, it's pretty unexpected that if I supply an if-none-match to the request, the server may keep the connection open for an arbitrary amount of time. I'd expect that behavior to be a side-channel of the normal 304 response. For example, it should only keep the connection open if I supply ?timeout=60 resource option or X-Modification-Timeout: 60 header.

Your code samples are incredibly hard to read, you should use a different library to generate those. I don't know if it's just a Chrome thing, but they look like this to me:


I'm curious if you guys did consider SignalR. Did you? If yes, yeah not use it?

We did consider SignalR with the Service Bus backplane (we run on Azure). We also considered node.js with Socket.IO/Redis, Firebase, and a number of other realtime systems. But when we looked into it we realized we would be duplicating a lot of code on the realtime side that was already there on the RESTful API side. With this approach we're able to do realtime with minimal modifications to our server and client side implementations that deal with our simple use case of keeping a resource up to date. Because we use AngularJS, simply updating the resource on the client side re-binds everything.

In the realtime stuff I've built I publish update notifications on different channels to Redis whenever data is saved from a model. Then I have a Node.js server that listens for those update notifications, fetches the new update once, and then pushes it out to all connected clients. This reduces a LOT of load on the server because if we have 300 clients connected, it still results in only one request to the server to fetch the new data and update all clients.

Even if you don't want to use a pub/sub and publish instant notifications when data is updated you could implement polling in a Node.js server and just have all the clients connect to it with Socket.io. Then when the Node.js server sees an update in the data it can push it out to all the clients.

This strategy also has the advantage that you don't have to change anything on the client if you decide to switch to a pub/sub in the future for more real time updates.

I've definitely done the separate channel thing in the past for update notifications and it does perform very well.

Our setup is a pub/sub system, where the "sub" happens implicitly with the request for a resource via the GRIP proxy and protocol and the "pub" happens when we update our models as well. The proxy acts a lot like node.js and Socket.IO would, but simply speaks pure HTTP on our RESTful resources instead of the Socket.IO protocol over their transports.

Have you looked into accepting Server Sent Events instead of long polling?

We didn't see much of a need to expand beyond long polling, if for nothing more than simplicity's sake. Realtime is a small feature in small parts of the application right now. Keeping it very simple and coupled with our RESTful API let us roll it out quickly.

Main reason to avoid long polling is the awful scalability (compared to plain old socket programming).

Processing the poll request certainly has a bit of a CPU/memory/network overhead. Though any sort of keep-alive would require something similar. I'm sure we'll get fancier with WebSockets when we have to rent too many new servers because of this stuff. The simplicity and elegance of overloading the RESTful HTTP system was the most appealing bit for me with this architectural experiment.

As I understand, Server Sent Events are plain old HTTP, unlike Web Sockets.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact