Eventual Consistency, or things will all work out…eventually

So we’re working with Amazon’s SimpleDB. It’s pretty sweet, though the ruby libraries for it are still a bit primitive. One of the problems you run up against when you’re writing integration tests against it is eventual consistency.

Take this test :

it "should save" do
  customer = Customer.create!(:name => 'bob', :email => 'bob@example.com')
  customer = Customer.find(customer.key)
  customer.name.should == 'bob'
end

The way SimpleDB works, you’re assured that Customer.find will work…eventually, but not right away.

For a couple days we contented ourselves to just run the integration tests a couple times until they didn’t error out. But that got old.

Enter “eventually” :

it "should save" do
  customer = Customer.create!(:name => 'bob', :email => 'bob@example.com')
  customer = eventually { Customer.find(customer.key) }
  customer.name.should == 'bob'
end

It’s a very simple method (below) that just retries the passed in block until it succeeds, timing out after 10 tries. Super simple, works like a charm. Thank you ruby.

Here’s the source :

def eventually(tries = 0, &block)
  yield
rescue
  raise if tries >= 10
  sleep 0.5
  eventually(tries + 1, &block)
end

I will say, I can’t help but smile every time I write “eventually” in a test… :)

Tags: , ,

Comments are closed.