Skip to content

Instantly share code, notes, and snippets.

@jdhollis
Created June 9, 2010 21:43
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jdhollis/432220 to your computer and use it in GitHub Desktop.
Save jdhollis/432220 to your computer and use it in GitHub Desktop.
handle_asynchronously for Resque
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
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
class SlowMethodJob < Resque::AsyncHandling::AsyncJob
@queue = :slow_methods
end
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
@jdhollis
Copy link
Author

jdhollis commented Jun 9, 2010

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…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment