Why ESI is Still Important, and How to Make it Better
Friday, 21 October 2011
More than ten years ago, I was working at Akamai and got involved in the specification of Edge Side Includes (ESI), sort of a templating language for intermediaries.
In that time, interest in ESI has grown, waned and been reborn. As far as I can tell, it’s implemented not only by Akamai and Oracle (the main forces behind it), but also in Varnish, Squid, and lots of other places too.
Back then, I had a strong suspicion that it’d die because people would see it as locking them into Akamai (or some other vendor). Why, then, is this limited, funny, embarrassingly simple little templating language still around?
In a word, it’s concurrency.
In the last couple of years, it’s become hot to build massively scalable Web servers by re-thinking how they handle concurrency; often using asynchronous, non-blocking single-process servers, rather than threads or multiple processes.
The benefits of this approach have been known for a long time; way before Dan Kegel wrote the C10K page, Web proxy servers like Squid (and its predecessor, Harvest) were using this approach because it’s the only sensible way to scale for them.
However, as folks are finding out when they use newer tools that implement these methods (e.g., Twisted, Node.JS), writing event-driven code is something you either love or hate. Many developers can’t stand it, especially for debugging (personally, I love it, but that’s just me).
So, ESI is a way to offer the massive concurrency of non-blocking, asynchronous servers in a way that’s easy to digest. Since fetching a URI doesn’t block, the only overhead is in stitching the page together, and you can control the overhead of that by limiting the language’s capability.
This makes ESI a great tool for building highly scalable dynamic Web sites without writing and debugging new code. Win.
Making ESI Better
ESI is, as mentioned, more than a decade old, and the Web has changed a lot in the intervening time. Even putting that aside, ESI isn’t exactly what we’d call Web-friendly. We can do better.
Over that time, I’ve had a number of thoughts about how to improve ESI as a language, which I’ve shared with some interested people privately. One of my back-burner projects has been to implement this, but I have to admit that this isn’t going to happen soon, since I’m busy doing several other things.
Instead, I’m going to dump those ideas here, and hope someone runs with them. Here are a few:
The biggest single way I can see to improve ESI is to make it possible to source variables from a URI. In other words, it should be possible to fetch a URI, parse the response (probably in JSON), and then reference the data returned when evaluating the template.
This would enable some really exciting things. Because variables are now just state, you can do things like cache user preferences – using plain old HTTP caching – and have that state be local to where it’s needed. When you update that state, it can be invalidated. ESI expressions now can have arbitrary, application-relevant input, instead of being limited to a few paltry request headers.
This could be what it looks like:
<esi:load name=”user_prefs” src=”http://prefs.example.com/{request.cookie.userid}”/> <!– … –> <esi:include src=”/{user_prefs.top_left_module}”/>
Here, you see some JSON being loaded into the user_prefs variable, form a URI that’s templates using a cookie that identifies the user, to drive how the page loads. This is very similar to a set of techniques I discussed a while back for composing services “RESTfully”, and it still works.
JSON also presents a way to clean up the variable model generally; instead of the random collection of variables, ESI 2.0 could instantiate a request object, with appropriate members like .method, .cookie, .headers, and so forth. It also brings about the possibility of making response attributes available as well, at least in the context of an include.
Going even further, JavaScript presents an opportunity to rally around a common, well-understood syntax for things like variable references, operators, and even common functions (e.g., string manipulation).
ESI:include desperately needs a timeout parameter, and a sensible means of specifying fallback content (probably as a child of the include element).
Deeper integration with HTTP is necessary; not only should it be possible to access arbitrary aspects of the incoming request, but it should be possible to affect more of the outgoing response; e.g., the status code. Likewise, finer-grained control over outgoing requests (generated by include as well as load) would be good (e.g., via attributes on the element).
There are lots of smaller, easier wins. Not requiring valid XML is an obvious one; integrating URI Templates is likewise a no-brainer. Cleaning up some of the cruft in the syntax would be nice; there are some elements that people just don’t need in there (e.g., esi:inline, the alt attribute).
Anybody up for it?
9 Comments
Jan Algermissen said:
Friday, October 21 2011 at 11:20 AM
Erik Mogensen said:
Friday, October 21 2011 at 11:52 AM
Mark Nottingham said:
Saturday, October 22 2011 at 9:30 AM
Ilya Grigorik said:
Saturday, October 22 2011 at 10:40 AM
Stefan Tilkov said:
Saturday, October 22 2011 at 12:56 PM
Mark Nottingham said:
Sunday, October 23 2011 at 3:57 AM
Jan Algermissen said:
Sunday, October 23 2011 at 7:46 AM
Ilya Grigorik said:
Monday, October 24 2011 at 5:44 AM
Mark Nottingham said:
Monday, October 24 2011 at 6:02 AM