On May 11, 2012, at 8:56 AM, Leif Hedstrom wrote: > On 5/10/12 10:21 PM, James Peach wrote: >> Hi all, >> >> I just committed a prototype remap plugin to the jpeach/lua branch that lets >> you write remap plugins in Lua. I'd say it's at proof of concept stage. It >> seems to basically work but it's never taken any real load. The error >> handling is pretty lackadaisical. >> >> Here's an example that should give you a feel: >> >> >> <https://git-wip-us.apache.org/repos/asf?p=trafficserver.git;a=blob_plain;f=plugins/lua/example.lua;hb=jpeach/lua> > > Very cool. It's actually pretty fast too. An extremely simple plugin. such as > > function remap(request) > url = request:url() > url.host = "origin.example.com" > url.path = "a/new/prefix" .. url.path > > request:rewrite(url) > end > > > Is only about 30% less throughput (but about 80% higher latency) compared to > a static remap.config rule. Pretty reasonable though (that's over 100,000 req > / sec with that Lua code).. Once the Lua code gets more complex, LuaJit would > be cool too :).
That sounds promising. It would be interesting to profile whether we are spending more time in the plugin binding or in the Lua environment. If it's the latter, then I think that we can change the build system to automatically use LuaJIT if it's available. >> I'd appreciate any comments about the API and the general approach. I think >> the most controversial aspect is that the plugin does not explicitly choose >> whether the remap evaluation chain continues. Request redirects and >> rejections terminate the chain; anything else allows it to continue. > > Yeah, lets gets some mileage and tests with this version, and have some > discussions. Should we perhaps add a CWiki page, documenting the current APIs > and decisions, and add proposals for additions / changes there ? https://cwiki.apache.org/confluence/display/TS/Lua+Plugin+API >> It's not clear to me yet how to extend the remap case to the general plugin >> case. Is the remap plugin useful enough to stand on it's own? > > Yeah, it's a whole different beast. A remap API is good to start with. As we work on the full Lua API, are we really gonna need the remap one as well? Since you can do remapping in a full plugin, maybe having a special plugin type just for remapping is unnecessary. In the C API it probably makes more sense because it's a much simplified model. > A couple of things that might be important from the get-go, that I can think > of: > > 1) Plugins has 4 different types of headers that they can work on (UA-req > header, Origin req-header, Origin resp-header and UA-resp header). Maybe it'd > be cool to make this more explicit also in the remap plugin APIs, so that we > only have one way of getting the headers? (Not all headers are available at > all stages through the SM though, for obvious reasons). > > 2) We can start populating the TS object with various functions that would be > of use. Yep. Bindings to standalone functions are usually pretty straightforward. > Some of them could even be useful for a remap plugin, for example the APIs to > set / get overridable configurations, statistics etc. Or perhaps that should > go into separate containers? I intended the 'ts' module to be a top-level package, so it could contain standalone functions, global variables or objects where it makes sense. > 3) For the request:redirect method, should it not take a response code? So > that it can do either a 301 or a 302. I think it'd be cleaner (symmetry) if > it was e.g. request:redirect(301, url) (which makes it look the same as > reject). Yeh I agree. We would need to address the ambiguity of the caller setting a status code that's not a 3xx. > I also find it a bit confusing that the second argument to reject can either > be the response message or the response body? In both cases, the optional second argument is the response body. There is some hokey content-sniffing code that tries to set the text/html content type if it thinks the body is HTML. I think that it would be better to have a legit response object with it's own status code, headers and body. That way callers can set the right content-type. > 4) For remap plugins, we have the notion of "instances" where one plugin has > a different run time environment for each remap rule using it. You obviously > use this for the Lua plugin. I'm thinking we should have something similar > for Lua scripts too? Actually Lua script get more "instances" than that. For each remap instance, the global "init" function is called once at load time and once for each ethread, since there is a Lua state for each thread. > Perhaps have all @pparam's that's after the mandatory script name getting > passed in as a table to the remap() implementation in the Lua script? This > would let me do e.g. > > map http://loki.ogre.com/bench http://something @plugin=lua.so > @pparam=loki.lua @pparam="bench" > map http://loki.ogre.com http://somethingelse @plugin=lusa.so > @pparam=loki.lua @pparam="all" I thought about this, but could not see a really convincing use case. Currently, I assume that all the @pparams are Lua scripts to load. If you need to add config into a Lua plugin, then it would be easy to put the config into a separate Lua script that is loaded, eg: map http://loki.ogre.com http://somethingelse @plugin=lua.so @pparam=loki.lua @pparam=all.lua > > and in loki.lua: > > function remap(request, params) > ... > end > > This helps alleviate the fact that we don't pass in the "To" and "From" URLs > to the plugin, Most of the remap plugins I looked at ignored the "To" URL, and I figured that the current UA request URL was of the most interest. I was not really sure what good the static URLs would be to a Lua script. > in fact, this is much more generic and usable. > > Cheers! > > -- leif >