Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add completion callback support, doc update

  • Loading branch information...
commit 2db509a34c7d26ea783a9438b87bec646fe52e5b 1 parent 849c436
@mperham authored
View
25 README.md
@@ -1,7 +1,11 @@
girl_friday
====================
-Have a task you want to get done sometime soon but don't want to do it yourself? Give it to your [girl friday](http://en.wikipedia.org/wiki/Girl_Friday)!
+Have a task you want to get done sometime soon but don't want to do it yourself? Give it to girl_friday! From wikipedia:
+
+> The term Man Friday has become an idiom, still in mainstream usage, to describe an especially faithful servant or
+> one's best servant or right-hand man. The female equivalent is Girl Friday. The title of the movie His Girl Friday
+> alludes to it and may have popularized it.
girl_friday is a Ruby library for performing asynchronous tasks. Often times you don't want to block a web response by performing some task, like sending an email, so you can just use this gem to perform it in the background. It works with any Ruby application, including Rails 3 applications.
@@ -9,13 +13,11 @@ girl_friday is a Ruby library for performing asynchronous tasks. Often times yo
Installation
------------------
-We recommend using [JRuby](http://jruby.org) or [Rubinius](http://rubini.us) with girl_friday. Both are excellent options for executing Ruby these days.
+We recommend using [JRuby 1.6+](http://jruby.org) or [Rubinius 2.0+](http://rubini.us) with girl_friday. Both are excellent options for executing Ruby these days.
gem install girl_friday
-Open your Rails application's Gemfile and add:
-
- gem 'girl_friday'
+girl_friday does not support Ruby 1.8 because of its poor threading support. Ruby 1.9 will work but not scale well.
Usage
@@ -25,15 +27,20 @@ Put girl_friday in your Gemfile:
gem 'girl_friday'
-In your Rails app, create a `config/initializers/queues.rb` which defines your queues:
+In your Rails app, create a `config/initializers/girl_friday.rb` which defines your queues:
- QUEUE = GirlFriday::WorkQueue.new('user_email') do |msg|
+ EMAIL_QUEUE = GirlFriday::WorkQueue.new('user_email', :size => 3) do |msg|
UserMailer.registration_email(msg).deliver
end
+ IMAGE_QUEUE = GirlFriday::WorkQueue.new('image_crawler', :size => 7) do |msg|
+ ImageCrawler.process(msg)
+ end
+
+:size is the number of workers to spin up and defaults to 5. Keep in mind, ActiveRecord defaults to a connection pool size of 5 so if your workers are accessing the database, you'll want to insure that the connection pool is large enough by modifying `config/database.yml`.
In your controller action or model, you can call `#push(msg)`
- QUEUE.push(:type => 'registration_email', :user => { :email => @user.email, :name => @user.name }))
+ EMAIL_QUEUE.push(:email => @user.email, :name => @user.name)
The msg parameter to push is just a Hash whose contents are completely up to you.
@@ -43,7 +50,7 @@ Your message processing block should **NOT** access any instance data or variabl
Error Handling
--------------------
-Your processor block can raise any error; don't worry about needing a begin..rescue block. Each queue contains a supervisor who will log any exceptions (to stderr or Hoptoad Notifier) and restart a new worker.
+Your processor block can raise any error; don't worry about needing a `begin..rescue` block. Each queue contains a supervisor who will log any exceptions (to stderr or Hoptoad Notifier) and restart a new worker.
More Detail
View
3  TODO.md
@@ -4,5 +4,4 @@ TODO
- job persistence
- clean shutdown (stop accepting web requests, drain queues)
- web admin UI with backlog, processing and completed metrics
- - nicer project homepage
- - completion callback support
+ - nicer project homepage
View
2  girl_friday.gemspec
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
s.authors = ["Mike Perham"]
s.email = ["mperham@gmail.com"]
s.homepage = ""
- s.summary = s.description = %q{Background processing via Rubinius's actor API}
+ s.summary = s.description = %q{Background processing, simplified}
s.rubyforge_project = "girl_friday"
View
2  lib/girl_friday.rb
@@ -1,7 +1,9 @@
begin
+ # Rubinius
require 'actor'
require 'girl_friday/monkey_patches'
rescue LoadError
+ # Others
require 'girl_friday/actor'
end
View
16 lib/girl_friday/work_queue.rb
@@ -2,7 +2,7 @@
module GirlFriday
class WorkQueue
Ready = Struct.new(:this)
- Work = Struct.new(:msg)
+ Work = Struct.new(:msg, :callback)
attr_reader :name
def initialize(name, options={}, &block)
@@ -11,8 +11,8 @@ def initialize(name, options={}, &block)
create_pool(options[:size] || 5, block)
end
- def push(work)
- @supervisor << Work[work]
+ def push(work, &block)
+ @supervisor << Work[work, block]
end
alias_method :<<, :push
@@ -31,10 +31,11 @@ def create_pool(size, processor)
supervisor = Actor.current
ready_workers = []
extra_work = []
- proc = Proc.new do
+ work_loop = Proc.new do
loop do
work = Actor.receive
- processor.call(work.msg)
+ result = processor.call(work.msg)
+ work.callback.call(result) if work.callback
supervisor << Ready[Actor.current]
end
end
@@ -42,7 +43,7 @@ def create_pool(size, processor)
Actor.trap_exit = true
size.times do |x|
# start N workers
- ready_workers << Actor.spawn_link(&proc)
+ ready_workers << Actor.spawn_link(&work_loop)
end
begin
@@ -65,8 +66,9 @@ def create_pool(size, processor)
end
end
f.when(Actor::DeadActorError) do |exit|
+ # TODO Provide current message contents as error context
@error_handler.handle(exit.reason)
- ready_workers << Actor.spawn_link(&proc)
+ ready_workers << Actor.spawn_link(&work_loop)
end
end
end
View
3  test/helper.rb
@@ -1,4 +1,7 @@
$testing = true
+# require 'simplecov'
+# SimpleCov.start
+
require 'test/unit'
require 'timed_queue'
require 'girl_friday'
View
13 test/test_girl_friday.rb
@@ -31,4 +31,17 @@ def test_should_handle_worker_error
end
end
+ def test_should_call_callback_when_complete
+ async_test do |cb|
+ queue = GirlFriday::WorkQueue.new('test', :size => 1) do |msg|
+ assert_equal 'foo', msg[:text]
+ 'camel'
+ end
+ queue.push(:text => 'foo') do |result|
+ assert_equal 'camel', result
+ cb.call
+ end
+ end
+ end
+
end
Please sign in to comment.
Something went wrong with that request. Please try again.