Tir 0.6 Up, With Background Task Goodies

I just uploaded the latest Tir 0.6 for everyone. This version has everything refactored into multiple modules, extensive unit testing, and built-in very easy to use background tasks. If you want to install it then follow the Tir Install guide to get it running.

Built-in Background Tasks
Over on Hype.la people can upload their pictures, which is great, except they usually want to upload monster photos that need to be scaled. There’s also things like search indexing, updating their static ads lists, and tons of stuff that really can just be don in a background task rather than hold up the browser.

Tir uses ZeroMQ so I figured, shouldn’t be too hard to make a nice little “background task” API. For those not familiar with the concept, a background task is basically a process you start that receives some kind of RPC to do work. You use these to offload long running processes like some of the stuff I mention above.

In Tir it’s dead simple, with a task process looking like this:

require ‘tir/engine’

function test(args)
Tir.dump(args)
end

Tir.Task.start { main = test, spec = ‘ipc://run/photos’ }
If you put this file in your app/ directory, then tir start will run it like it’s a normal handler. The difference is, instead of taking requests from Mongrel2 it accepts simpler messages on the 0MQ socket you have in spec.

Here’s an example handler that does receive messages from Mongrel2, but sends the headers off to the above background task and then fires off an OK reply right away:

require ‘tir/engine’

local conn = Tir.Task.connect { spec = ‘ipc://run/photos’ }

function main(web, req)
conn:send(‘photo’, req.headers)
web:ok()
end

Tir.stateless {route=’/Task’, main=main}
If you were to hit curl http://localhost:6767/Task then this would return OK, but you’d see the background task actually receive the headers and print them out.

Changing The 0MQ Socket
This is very simple right now, but already you can configure the socket that’s used to match your needs. It normally defaults to a raw PUB/SUB socket with out subscriptions or idents, but you can change that with a different config:

Tir.Task.start {
main = test, spec = ‘tcp://0.0.0.0:4545’,
recv_ident=’PHOTO_PROCESSOR’, socket_type=zmq.PULL
}
This would bind a listener socket to whatever port 4545 and use it like a PULL socket (round robbin) rather than SUB. You could then connect with:

local conn = Tir.Task.connect {
spec = ‘tcp://background-cluster.myco.com:4545’,
send_ident=’client-34343′, socket_type=zmq.PUSH
}
That could be a client connection to the above using the domain name background-cluster.myco.com on port 4545 and doing a PUSH socket.

You can also pass in a subscribe option to Tir.Task.start so that, when it uses the SUB socket, it will be subscribed to only messages with a certain target.

Significance Of This
It’s early, but this means that Tir will let you convert slow long running handlers into fast tight async clusters by just moving the code into a background task and having the handler shoot data at it. Since it’s so easy to start these tasks up and make them, and since you get 0MQ goodies, this means you shouldn’t need to use many of the current background systems.

Of course you’d probably need a bit more on top of this depending on the use case. You’d need to store state, establish some kind of “protocol” for what the task accepts, and probably need to find a way for tasks to report back. But, this base lets you create all that.

Already this kind of simple background task is helping me rework some parts of Hype.la that were starting to suck. I’ll have more information on patterns for using this as I actually apply it.

.

Leave a Reply

Your email address will not be published. Required fields are marked *