Skip to content
This repository has been archived by the owner on May 26, 2021. It is now read-only.

Failures 2.0

tarcieri edited this page Apr 4, 2013 · 8 revisions

The Resque::Failure API presently suffers from a lot of problems. Here are some of the major ones:

  • Too many singletons: Have a look through failure.rb and failure/base.rb and you will notice that the API is almost exclusively singletons. There are hardly any instance methods (base.rb defines a #save method and that's really it)
  • Failures aren't objects: There's a clear reason why there are so many singletons: when you ask for a failure, what you get back isn't a Resque::Failure object. It's just a JSON blob parsed into hash literals. Want to know anything about the failure? You have to dig through the JSON structure, which depending on where it originated from (lots of people like implementing Resque-alikes in other languages) may or may not have the elements you care about. IMO, when you ask for a failure, you should get a Resque::Failure object.
  • Failures don't have unique IDs: I think that every failure should be identified by a unique ID (similar to a primary key) and that all APIs should accept these IDs. I have done some work with the existing code to try to facilitate this, but the API isn't great.
  • Too many arguments: Looking at failure.rb#79, Resque::Failure#each already takes 5 arguments. This seems like a pretty clear candidate for an options hash.
  • Wacky APIs: For whatever reason, by default Resque::Failure.all only returns one failure object (as a parsed JSON blob). To actually return all failures, we need to consult Resque::Failure.count first, then pass that into Resque::Failure#all. It seems pretty clear to me this API is in need of some love.
  • Multiple backends with inconsistent logic: To see how painful this is, check out resque-web's RetryController. ZOMG! That is some gnarly code, working around the above mentioned deficiencies and inconsistencies between the existing failure backends. Ideally, all backends would be unified under a consistent API. That was the original goal of the Resque::Failure module, but unfortunately it falls quite short.

The Path Forward

These are @tarcieri's suggestions for fixing the API:

  • More like ActiveRecord: I think an ActiveRecord-alike API would make Resque::Failure intuitive to anyone who's familiar with ActiveRecord, and provides a fairly decent pattern for how these sort of persistence APIs should work. Calling Resque::Failure.all(:queue => 'myqueue') should return an array of Resque::Failure objects. I should be able to do things to a Resque::Failure object via instance methods, like #destroy it or #retry it.
  • Multiple failure queues or GTFO: Resque originally supported a single 'failed' queue, unfortunately as more people started using it, this was quickly shown not to scale very well. The failure API should be designed around the idea that every queue has its own individual failure queue. IMO, Resque::Failure::Redis should be completely deleted from Resque 2.0, and the Resque::Failure::RedisMultiQueue backend should replace it.
  • Support ActiveRecord as a failure backend: Redis queues are just not a great way to store failures. If one person views the failure page and deletes a failure, and someone else tries to delete a different failure, the second person will end up deleting the wrong failure, because its position in the failure queue has changed. THIS IS BAD! I'm not saying that we should dump a Redis-based failure backend, but it's quite clear that the failure system has outgrown what Redis can do, and really needs a database that can do better querying of the data and can represent each failure with a primary key. I think it would really make sense to (optionally) support an ActiveRecord-based failure backend which provides a lot more rigorous semantics around how failures are handled.
Clone this wiki locally