The Real-time Web: How to Get Millisecond Updates with REST
engineering.imvu.com
engineering.imvu.com
"[...] even though we have JavaScript code running in the browser, and it knows about the invalidation of a particular URL, it cannot tell the browser cache that the data at the end of that URL is now updated.
Instead, we keep a local cache inside the web page. This cache maps URL to JSON payload, and our wrapper on top of XMLHttpRequest will first check this cache, and deliver the data if it’s there. When we receive an invalidation request over IMQ, we mark it stale (although we may still deliver it, for example for offline browsing purposes.)"
I thought that the traditional approach to this would be to add a cache-buster [1] to the query string. Couldn't the Javascript code that knows there's a change update the cache-buster argument and refetch the URL? Then they wouldn't need their own cache implementation.
[1] A cache-buster is typically a random value (or timestamp) included as a query-string argument on the URL. This value has no meaning to the server, but because the URL string has changed the browser can't make any assumptions about what the return value would be, and is therefore forced to make a request to the server.
EDIT: I think I see now - what they refer to as "the cache" is more complex than I had thought; it seems somewhat more analagous to the state in a React app, in that it is triggering UI updates and isn't just a dumb layer between the client and server.
We like HATEOAS and dislike clients editing URLs.
As an aside for search and filtering, we do allow clients to add query parameters to existing endpoints.
I've also been working on a protocol definition for REST updates called LiveResource. Anyone interested in this problem space, please send feedback. :) https://github.com/fanout/liveresource
I'd love to see CouchDB used more and checked first as a starting point for anything in the space of live update of data, because it just works so well. Too many people re-invent the wheel left and right in this domain.
To do it, one useful component is PouchDB (http://pouchdb.com/), which is a data store in the browser. You just hook it to whatever backend you want and access the data with a straightforward javascript API.
There's also the much larger (in scope) Hoo.ie, but I can't talk much about it...
Unfortunately I don't have any links for you, I'm looking for experiences just like you ...
To start: I'd like to have seamless R/R via stateless HTTP as well as websockets. I'd like to also implement transparent push events via SSEs and the aforementioned socket transport.
Naturally, inter-service communication would use the already-present MQ.
The workflow in this true "microservices a la carte" solution would look like:
Initial, one-time setup:
1) Set up NSQ (or other supported MQ - I'll start with NSQ)
2) Set up standard, client-facing frontend servers (stateless HTTP, sockets, SSE) bound to queue.
3) Set up DNS names for frontend load-balancers (ELB, heroku load balancing, whatever) for each frontend.
---
Writing a service:
1) In your language/framework/stack of choice, create a new project, include standard-sauce, language-specific server library.
2) Write a function to do what you want. (retrieve a list of users, create a post, whatever)
3) Register/bind the aforementioned function to a specific, standard, interfaceable name (using the service library)
4) Configure service library to connect to initially-setup message broker.
The end-goal is to have a standard RPC interface, standard pub/sub interface, standard message fabric across front-end clients (browser, mobile, whatever) and back-end clients (inter-service communication).
---
Internally, a call message might look like:
{method: "get", action: "users", requestId: "21739dfe-fbeb-4da9-b698-c5720cbc488d", timestamp: "2014-12-25xxxxxx"}
This will seamlessly map to:
HTTP GET (Frontend): http://api.mydomain.com/users
Websocket message (stateful) (Frontend): {method: "get", action: "user"}
ServiceLibrary call (Ruby): "Project.call(:get, :users)"
ServiceLibrary call (Node): "project.callFunc('get', 'users', callback)"
.. and you get the idea. No prescription necessary.
---
If you like ActiveRecord, Ruby, the Rails stack: rip out ActionController, rip out Rack, use the stuff you want.
If you want to use some of the amazing JS frontend rendering toolchains: hook em up.
If you need to write a simple, highly-concurrent microservice, try Go.
Rather than prescribe an entire solution (a la Meteor, Derby, etc.), take the best tool for the job and throw it at the situation.
---
The scaling story is cool, too: if your ActiveRecord-driven microservice is unable to keep up I/O throughput, rewrite it or just spin more instances up. Totally shared-nothing in this case.
Also, messaging, decoration, online status, ... Lots of data could, and should, be real time! The cool thing is that it all is deployed and works at IMVU scale.
Apologies for typos - phone auto correct.
I still don't quite know when I should use graph database but I imagine for social networking type of websites it is a must (since a standard RBDMS or NoSQL gets too verbose).
Graph structure based features like in Friendster are expensive and don't scale well, that's why Friendster failed. And MySpace and FB removed that features (friends of friends of friends) early on.