At Inquisix, we help sales professionals exchange trusted referrals. To do that requires several background tasks, some that could take 10-15 minutes to process. Obviously, I can’t make a client wait for that, so I needed a system that could handle background tasks. At first, I started with backgroundrb, and it worked just fine. Backgroundrb was in production for two months while Inquisix grew. However, there were a few things about backgroundrb that bothered me:
- It uses a lot of memory. Every worker creates at least one process. Plus, there is a master process to watch everything and deal with communication. It doesn’t take much before you end up with 5-6 processes. I had to upgrade my test server just to deal with the extra memory requirements.
- It’s not easy to build a queue with control over threads without creating a ton of processes.
- Too many times, I wanted to do something pretty straight forward, but I had to dig through the backgroundrb code to figure out the backgroundrb way. For example, don’t ever call sleep in a backgroundb thread pool. You need to call next_turn instead.
After a while, I decided to look for a simpler way that would scale better without using so much memory. I decided a more traditional queue system would work better for me. At a former company, I built up an enterprise system based on queues that processes millions of transactions across dozens of servers. Something based on queues would work for me, but I did not want to take on the complexity of JMS, ActiveMQ (or some other queue), ActiveMessaging, etc. As usual with Ruby projects, I looked around on the web. Within a few minutes, I came across Starling and Sparrow. Both a Ruby queue systems using the memcached interface. That means I can use the memcache-client gem that I already use. Starling was developed at Twitter for background processing, so I figure it’s got some testing behind it. Sparrow is newer, but basically the same. However, there isn’t much experience with Sparrow, so I settled on Starling as my queue server.
To install Starling:
sudo gem install starling
sudo gem install memcache-client
Now, I needed a way to use my new queue server for background tasks. Again, a few minutes of looking, and I found Workling. It didn’t have everything I wanted, but it was nice and simple, and it had almost everything I wanted. I use Piston for all my plugins, so here is how to install with that:
piston import http://svn.playtype.net/plugins/workling/ vendor/plugins/workling
svn commit -m "added workling"
Make sure you commit now because we will be making some changes to Workling later. Piston will get confused and toss your changes if you don’t commit first.
Client Code
First, create a worker in app/workers/my_worker.rb
class MyWorker < Workling::Base
def do_something_big(options = {})
SomeModel.do_something_big(options[:some_arg])
end
end
Anything in app/workers that inherits from Workling::Base will get picked up automatically as a worker. Workers are basically listeners on a Starling queue. By default, Workling defines queues based on class and method. There will be a queue for every method in every class that inherits from Workling::Base.
Now, you can call your worker asynchronously anywhere like so:
MyWorker.asynch_do_something_big(:some_arg => 5)
Starling Runner
To use the Workling’s Starling runner, you need to setup your environment like so:
Workling::Remote.dispatcher = Workling::Remote::Runners::StarlingRunner.new
I add this line to all my environment files (development.rb, etc.). Workling is nice in that if you comment out the above line, all the MyWorker.asynch_* calls will become synchronous calls — nice for debugging!
The Starling runner takes care of several things:
- Mapping of queue names to worker code. this is done with Workling::ClassAndMethodRouting, but you can change the queue routing pretty easily.
- There’s a client daemon that waits for messages and dispatches these to the responsible workers. if you intend to run this on a remote machine, then just check out your rails project there and start up the Starling client.
Now, fire up Starling, your app, and the workling runner, and your are processing background tasks. Don’t forget to edit config/starling.yml first to tell Workling where Starling is running.
sudo starling -d
script/server
script/workling_starling_client start
What I ended up with was much better for what I was doing. This combination processed my background tasks faster and more reliably. It is much easier to add new workers and call them. Finally, it uses a whole lot less memory, so my end user application performs better. Basically, it wins on all fronts for me.
Next time, I will share the changes I made to Workling to support threads and provide the necessary configuration to ensure that everything stays running in production.

[...] – written by Blaine Cook at Twitter – Starling is a Message Queue Server based on MemCached – written in Ruby – stores jobs in memory (message queue) – Ruby client: for instance Workling – documentation: some good tutorials, for example the railscast about starling and workling or this blog post about starling [...]
Hi Dave,
Every time I look for some info on Starling/Workling, I end up on your blog
. It seems it is the most expert place to find advice on these two guys! So I thought I would ask my question here.
On a user request, my app has to run a fairly complex optimization algorithm. In fact, it is so time consuming that I have to run it in the background and “slice” it into smaller pieces that talk to each other. I have done it with Starling and Workling:
the algorithm is run as workers, and they communicate with each other passing messages with Starling.
It works great when I have only one Mongrel, but it starts failing when I deploy and use Passenger. I get random MemCache errors:
- MemCache::MemCacheError: No connection to server (localhost:11211 DEAD (Timeout::Error: IO timeout), will retry at xxx and
- MemCache::MemCacheError: IO timeout
They are really hard to track down since they seem to be random (i.e. sometimes things work great, but the next time they fail).
I know that Passenger is a bit specific when it spawns processes and it requires a specific setup. But I am running on Conservative mode to be “safe” – still, it fails.
Since my understanding is you are using the same setup (Starling/Workling/Passenger), have you had any problems? Are you using the memcache-client gem with Starling, or the memcached one?
Thanks a lot!
Pierre
Pierre, I recall seeing something like this, but I can’t remember the details. Unfortunately, my computer is not available until Thursday. I will take a look then.
Thanks a lot Dave. If you find out and could share some hints on how you managed to overcome this problem it would be fantastic – I am definitely struggling with this, and there is not that much info around…
I came across this fairly recent post:
http://plasti.cx/2010/02/03/getting-passenger-to-play-nice-with-interlock-cache_fu-and-memcached
where they say memcache-client just doesn’t work with Passenger and I was getting really concerned…
I can’t seem to find anything specific in my code. I processed several million messages with starling, workling, and passenger without a problem. The only thing I can think of is to make sure the :multithread arg is true when you init memcache-client. The issue here seems to be with starling which means that passenger may not have anyhing to do with it. Your workers are running in the workling processes, not passenger.
Are you getting the errors from your workers making the calls to each other vs. passenger app trying to add a new workling message to the queue?
Thanks a lot Dave – you pointed me in the right direction. My problem had nothing to do with Passenger. It took me a while to figure this out, but I think it was just a consequence of the load (I was testing with multiple simultaneous calls to my app). Indeed, I didn’t realize that the default timeout for memcache was 0.5s. Since I am making quite a lot of calls to the queue, some could not get completed in time and I was missing the respective message. When I set a long memcache timeout, the problem disappears.
I have to say it is kind of weird, since I have to set it really long (more than 10s, or even leaving it to nil). Something is blocking somewhere, I need to investigate.
Anyway, thank you very much for your help on this.
Found your web sites on AskJeeves, great information, but the site looks awkward in doing my browser setup, but gets results fine in IE. proceed figure.
Hi Dave,
I know this is a very late comment, but I’ll shoot anyway.
What if you want to run some tests that incorporate workling on the same box you develop on? Or what if your development box is the same as your production box (for perhaps a different branch of your code)?
It seems workling only respects RAILS_ENV and there is no way I can see to get this to play nicely.
I can do something like manually set RAILS_ENV=test in my tests, then set it back to RAILS_ENV=development afterwards, but that seems really hacky and far less than ideal.
any suggestions would be appreciated.
thanks,
Lee.
I’m not sure what you are trying to accomplish by doing this? If you set RAILS_ENV=test, no queue will be used and your workers will be called synchronously. This will allow for testing to happen normally. You can also set your environments to use Asynch calls as well. However, if you do that, then your tests will only ensure that a message will be put on the queue. There will be no no way to know if anything happened as a result of the message.
Hi,
I am with a staffing agency looking for a VP level person. Location is RI. Was hoping you may know someone to fit the role. A few particulars are below.
#1 management skills-someone who has managed up to 20
#2 relevant technical skills/knowledge—PHP
Someone who has/can code PHP
Have they done technical development? Can they hold their own in a group of talented PHP developers?
The rest—social media and industry background is icing on the cake
Having built SAAS PHP architecture is a plus/helpful
[...] luminor marina panerai marina panerai orologi panerai pam 0063 panerai prezzi panerai price list panerai price list 2011 panerai radiomir Filed under: Uncategorized Leave a comment Comments (0) Trackbacks (0) ( [...]
[...] watches used rolex cartier cartier trinity ring b4106200 cartier 593120 Click here to cancel [...]