Backgrounded: A Simple Wrapper for Ruby Background Tasks
Like Ryan Sonnek, I've dabbled with a few different ways to run background processes in my Ruby apps, even resorting to knocking together my own (far from perfect) solution. As Ryan says on his blog, many popular libraries have complicated interfaces and don't "feel right".
I tend to disagree, however, with his statement that every ruby background job solution sucks, and I'm sure he doesn't really mean it. Although his offering, Backgrounded, is refreshingly simple and concise, it's effectively just a wrapper for other solutions.
With Backgrounded, if you want a certain method to always run in the background, you can specify it like this:
class User backgrounded :do_stuff def do_stuff # do all your work here end end
...and then just call that method in the normal way. The actual background work can be taken care of by a handler of your choice, but delayed_job comes bundled.
Ryan's meta-programming approach for declaring background tasks doubles-up as documentation, and puts the focus on the individual methods rather than requiring you to create separate classes for your jobs.
Get Backgrounded as a gem or download the source from Github.
July 23, 2009 at 9:30 pm
Nice work; I like the automatic handling of methods to background tasks...
I used a similar interface when I made theman to drive scheduled background workers:
http://github.com/jcapote/theman/tree/master
July 23, 2009 at 11:58 pm
delayed_job has this exact functionality, although as a method in its own namespace. so what's the catch here?
July 24, 2009 at 1:35 am
"every ruby background job solution sucks"?
send_later(:do_stuff)
vs
do_stuff_backgrounded
Did we miss something?
July 24, 2009 at 5:30 am
The blog post does a better job explaining this, but the reasons this library exists are because:
* the API should be clean/concise. the alternative delayed_job API is okay, but not great.
* testability. none of the libraries I've worked with have been particularly good about working in unit tests.
* portability. It's simple to implement your own worker queue, and delayed_job is included by default just to help users get up and running. It would be trivial for me to extract that into a separate gem and leave the core as platform agnostic.
IMO the API is the absolute most critical piece to the puzzle.
July 24, 2009 at 7:34 pm
I've used all kinds of background process implementations too, including Backgroundrb and delayed_job. I'm wondering: for tasks that can be run by a rake task, is there any reason NOT to run them using backticks and a forked process? E.g.:
Kernel.fork { `rake export:begin` }
We're using this on a project and it seems to work fine, not to mention being very simple to deal with. But if there is a compelling reason not to do this, I'm all ears.
July 25, 2009 at 10:02 pm
The intention is good but the implementation is already flawed despite the limited amount of code:
- Why `foo_backgrounded' instead of the more natural `background(:foo)' (like `send_later')?
- When `Backgrounded::Model' is included, a bunch of unexpected `include's and `extend's happen at inclusion time and each time `backgrounded' is called... with empty modules! Waste of system memory. Looks like dirt from a code template.
- Calling `to_s' inside a string interpolation: time to read the Pickaxe.
- References an module from a shared namespace (`Handler') with the outter module name syntax (`B::Handler' though already inside `B').
- `Handler' being module containing several handler types, it should be named with the plural form. And those types shouldn't be suffixed with "Handler" as they're already namespaced.
- Performs an include in `Object' (!).
- Still, the tests are kind of decent, for now.