At RailsConf Europe, Yehuda Katz showed off a small yet totally useful feature of Merb. A method called run_later that does nothing more than queue the block it receives as an argument to be executed after the request is done.

After the announcement that Rails 2.2 would be thread-safe, and after seeing Nick Sieger's work on a connection pool for ActiveRecord I thought that this feature should be usable with Rails as well.

So without further ado, run_later is now available as a plugin for Rails. It simply fires of a separate thread when your application starts and will work through whatever you put in its queue.

The worker thread will be on a per-process basis due to Ruby's in-process threading. So each Mongrel you start will have its own worker thread. It's not the place to put long running tasks that need some kind of separation or need to run in the order they arrive in the queue. For that, turn to tools like Starling/Workling or ActiveMessaging. Also, it doesn't use a persistent queue, so if you have important messages to deliver, again, turn to more advanced tools.

But for smaller tasks that don't need to run within the context of the request or would potentially block it, run_later is pretty much all you need.

Integrating it in your controller is simple:

The only requirement: Rails 2.2, the current edge version works fine. With any version lower than that especially the behavior of ActiveRecord will be unpredictable. But if you're using Rails 2.2, give it a go, and let me know about your results. Mind you, I haven't put this into production myself, so some stability testing is still on my list.

I'm planning to throw in some kind of scheduling so that you can say something like run_later :in => 10.minutes.

Credit where credit is due: To Ezra for adding the code to Merb, for Yehuda to mention the feature at the BoF session and giving me the idea to port it. Not to forget the effort to make Rails thread-safe in the first place. I merely adapted their code to work with Rails, and threw in some tests as well.

Tags: rails, ruby

I'm not religious about anything, but if there's one thing I adopted and applied rigorously over the last years it's testing. Out of that habit I've developed using some principles that drive my writing of tests.

  • You don't have to avoid stubbing and mocking everything, but you can try

    Reducing the number of collaborators will result in smaller methods which are in turn easier to test. In the end stubbing things out is better than having to have complex dependencies in place to run a test suite.

  • Test everything that's important

    And if it's not important, why not just throw it out? If you can't throw it out, then it's probably important. So make sure you write tests for it. Simple as that.

  • If you don't know what else to do, write a test

    Stop thinking about how the code should look, start thinking what you want it to do. Some people call it working test-first, I just use it to find out how I want the code to work from the outside. When you put every aspect of the method in question into test cases, the way it should work will take shape naturally.

  • The testing framework is not your biggest problem

    While I prefer the style of RSpec and Shoulda for writing tests, it's usually not the problem of which of them you actually use. The point is to write tests, choose whichever framework will make that the easiest for you. You can write tests with all of them.

  • Don't DRY out your tests

    Tests are about readability. They're supposed to tell the reader what the code is supposed to do, without having to browse up and down in the test file to find methods that are used to create objects, or worse yet, through fixtures. Don't try too hard to put common code to setup scenarios into separate methods. It's just not important in tests. Create your scenarios where you need them, or use tools like factory_girl, where you collect object scenarios in a single file.

    Don't put too much code into separate methods for reuse in multiple test cases. If you do, make sure you name them in a way that will ensure readability, and think twice before you move code away from the point where other developers will look first.

  • Keep your tests small

    Instead of testing everything in one test method, create a separate test for every aspect of the method under test. The tests are easier to read and errors are easier to find.

Writing good tests is an art in itself, but trying your best to learn and constantly improve it is the best thing you can do for yourself in my opinion.

To get a weird RSpec mock error working again, I tried to look for a solution to dynamically add and remove methods on each spec run due to some odd ends in the current RSpec edge version. Sounds weird I know, but what are you gonna do. I went for a different solution in the end, but still this was good to know.

You need to get the class' singleton class to remove the method again. Everything else will fail miserably. But this works like a charme:

Tags: ruby