Created
June 9, 2010 21:43
-
-
Save jdhollis/432220 to your computer and use it in GitHub Desktop.
handle_asynchronously for Resque
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Resque | |
module AsyncHandling | |
# To disable (in config.after_initialize): | |
# Resque::AsyncHandling.enabled = false | |
mattr_accessor :enabled | |
self.enabled = true | |
def handle_asynchronously(original_method, params = { }) | |
if enabled | |
now_method = "#{ original_method }_now" | |
later_method = "#{ original_method }_later" | |
metaclass = class << self; self; end | |
metaclass.send(:define_method, later_method) do |*args| | |
unless params[:when].present? | |
Resque.enqueue "#{ params[:in].to_s.singularize.classify }Job".constantize, self.to_s, now_method, *args | |
else | |
Resque.enqueue_at params[:when].call, "#{ params[:in].to_s.singularize.classify }Job".constantize, self.to_s, now_method, *args | |
end | |
end | |
metaclass.send :alias_method, now_method, original_method | |
metaclass.send :alias_method, original_method, later_method | |
end | |
end | |
class AsyncJob | |
def self.perform(the_class_name, the_method, *args) | |
the_class = the_class_name.constantize | |
the_class.send the_method, *args | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'spec_helper' | |
class SlowMethodJob < Resque::AsyncHandling::AsyncJob | |
@queue = :slow_methods | |
end | |
describe Resque::AsyncHandling do | |
describe "#handle_asynchronously" do | |
context "when enabled" do | |
before(:each) do | |
@original_enabled_setting = Resque::AsyncHandling.enabled | |
Resque::AsyncHandling.enabled = true | |
class TestEnabledAsyncHandling | |
extend Resque::AsyncHandling | |
def self.do_slow_method(a, b, c) | |
[a, b, c] | |
end | |
handle_asynchronously :do_slow_method, :in => :slow_methods | |
end | |
end | |
it "defines a 'now' method" do | |
TestEnabledAsyncHandling.public_methods.should include('do_slow_method_now') | |
end | |
it "defines a 'later' method" do | |
TestEnabledAsyncHandling.public_methods.should include('do_slow_method_later') | |
end | |
it "aliases the provided method to the 'later' method" do | |
mock(Resque).enqueue SlowMethodJob, 'TestEnabledAsyncHandling', 'do_slow_method_now', 1, 2, 3 | |
TestEnabledAsyncHandling.do_slow_method(1, 2, 3).should_not == [1, 2, 3] | |
end | |
describe "the 'later' method" do | |
context "when no future time has been specified" do | |
it "enqueues a job in the provided queue for immediate execution" do | |
mock(Resque).enqueue SlowMethodJob, 'TestEnabledAsyncHandling', 'do_slow_method_now', 1, 2, 3 | |
TestEnabledAsyncHandling.do_slow_method(1, 2, 3) | |
end | |
end | |
context "when a future time has been specified" do | |
let(:the_future) { lambda { 5.minutes.from_now } } | |
before(:each) do | |
class TestEnabledAsyncHandling | |
extend Resque::AsyncHandling | |
def self.do_slow_method(a, b, c) | |
[a, b, c] | |
end | |
handle_asynchronously :do_slow_method, :in => :slow_methods, :when => lambda { 5.minutes.from_now } | |
end | |
end | |
it "enqueues a job in the provided queue for execution after the specified time" do | |
Time.freeze do | |
mock(Resque).enqueue_at the_future.call, SlowMethodJob, 'TestEnabledAsyncHandling', 'do_slow_method_now', 1, 2, 3 | |
TestEnabledAsyncHandling.do_slow_method(1, 2, 3) | |
end | |
end | |
end | |
end | |
describe "the 'now' method" do | |
it "calls the original code of the provided method" do | |
TestEnabledAsyncHandling.do_slow_method_now(1, 2, 3).should == [1, 2, 3] | |
end | |
end | |
after(:each) do | |
Resque::AsyncHandling.enabled = @original_enabled_setting | |
end | |
end | |
context "when disabled" do | |
before(:each) do | |
@original_enabled_setting = Resque::AsyncHandling.enabled | |
Resque::AsyncHandling.enabled = false | |
class TestDisabledAsyncHandling | |
extend Resque::AsyncHandling | |
def self.do_slow_method(a, b, c) | |
[a, b, c] | |
end | |
handle_asynchronously :do_slow_method, :in => :slow_methods | |
end | |
end | |
it "does nothing" do | |
TestDisabledAsyncHandling.public_methods.should_not include('do_slow_method_now') | |
TestDisabledAsyncHandling.public_methods.should_not include('do_slow_method_later') | |
end | |
after(:each) do | |
Resque::AsyncHandling.enabled = @original_enabled_setting | |
end | |
end | |
end | |
end | |
class TestAsyncJob | |
def self.the_method(a, b, c) | |
[a, b, c] | |
end | |
end | |
describe Resque::AsyncHandling::AsyncJob do | |
describe "#perform" do | |
it "calls the provided method with the provided arguments on the the provided class" do | |
a, b, c = [1, 2, 3] | |
Resque::AsyncHandling::AsyncJob.perform("TestAsyncJob", :the_method, a, b, c).should == TestAsyncJob.the_method(a, b, c) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SlowMethodJob < Resque::AsyncHandling::AsyncJob | |
@queue = :slow_methods | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TestAsyncHandling | |
extend Resque::AsyncHandling | |
def self.do_slow_method(a, b, c) | |
[a, b, c] | |
end | |
handle_asynchronously :do_slow_method, :in => :slow_methods, :when => lambda { 5.minutes.from_now } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Use this quite extensively at work so I don't have to have a full-on Resque environment running locally (unless I want to). Maybe one of these days I'll break this out into a proper plugin…