Skip to content

Commit

Permalink
Refactor PerformableMethod so it's easier to extend with multiple bac…
Browse files Browse the repository at this point in the history
…kends
  • Loading branch information
bkeepers committed Jan 19, 2010
1 parent c9e9775 commit 35a2808
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 37 deletions.
10 changes: 10 additions & 0 deletions lib/delayed/backend/active_record.rb
@@ -1,5 +1,15 @@
require 'timeout'

class ActiveRecord::Base
def self.load_for_delayed_job(id)
find(id)
end

def dump_for_delayed_job
"#{self.class};#{id}"
end
end

module Delayed
module Backend
module ActiveRecord
Expand Down
16 changes: 16 additions & 0 deletions lib/delayed/backend/mongo.rb
@@ -1,5 +1,21 @@
require 'mongo_mapper'

module MongoMapper
module Document
module ClassMethods
def load_for_delayed_job(id)
find!(id)
end
end

module InstanceMethods
def dump_for_delayed_job
"#{self.class};#{id}"
end
end
end
end

module Delayed
module Backend
module Mongo
Expand Down
51 changes: 28 additions & 23 deletions lib/delayed/performable_method.rb
@@ -1,8 +1,16 @@
class Class
def load_for_delayed_job(arg)
self
end

def dump_for_delayed_job
name
end
end

module Delayed
class PerformableMethod < Struct.new(:object, :method, :args)
CLASS_STRING_FORMAT = /^CLASS\:([A-Z][\w\:]+)$/
AR_STRING_FORMAT = /^AR\:([A-Z][\w\:]+)\:(\d+)$/
MM_STRING_FORMAT = /^MM\:([A-Z][\w\:]+)\:(\w+)$/
STRING_FORMAT = /^LOAD\;([A-Z][\w\:]+)(?:\;(\w+))?$/

class LoadError < StandardError
end
Expand All @@ -15,42 +23,39 @@ def initialize(object, method, args)
self.method = method.to_sym
end

def display_name
case self.object
when CLASS_STRING_FORMAT then "#{$1}.#{method}"
when AR_STRING_FORMAT then "#{$1}##{method}"
when MM_STRING_FORMAT then "#{$1}##{method}"
else "Unknown##{method}"
end
end

def display_name
if STRING_FORMAT === object
"#{$1}#{$2 ? '#' : '.'}#{method}"
else
"#{object.class}##{method}"
end
end

def perform
load(object).send(method, *args.map{|a| load(a)})
rescue PerformableMethod::LoadError
# We cannot do anything about objects which were deleted in the meantime
# We cannot do anything about objects that can't be loaded
true
end

private

def load(obj)
case obj
when CLASS_STRING_FORMAT then $1.constantize
when AR_STRING_FORMAT then $1.constantize.find($2)
when MM_STRING_FORMAT then $1.constantize.find!($2)
else obj
if STRING_FORMAT === obj
$1.constantize.load_for_delayed_job($2)
else
obj
end
rescue => e
Delayed::Worker.logger.warn "Could not load object for job: #{e.message}"
raise PerformableMethod::LoadError
end

def dump(obj)
case obj
when Class then "CLASS:#{obj.name}"
when ActiveRecord::Base then "AR:#{obj.class}:#{obj.id}"
when MongoMapper::Document then "MM:#{obj.class}:#{obj.id}"
else obj
if obj.respond_to?(:dump_for_delayed_job)
"LOAD;#{obj.dump_for_delayed_job}"
else
obj
end
end
end
Expand Down
17 changes: 5 additions & 12 deletions spec/delayed_method_spec.rb
Expand Up @@ -11,15 +11,6 @@ def say_hello
end
end

class ErrorObject

def throw
raise ActiveRecord::RecordNotFound, '...'
false
end

end

class StoryReader

def read(story)
Expand Down Expand Up @@ -65,7 +56,9 @@ def read(story)
end

it "should ignore ActiveRecord::RecordNotFound errors because they are permanent" do
job = ErrorObject.new.send_later(:throw)
story = Story.create :text => 'Once upon...'
job = story.send_later(:tell)
story.destroy
lambda { job.invoke_job }.should_not raise_error
end

Expand All @@ -75,7 +68,7 @@ def read(story)

job = Delayed::Job.find(:first)
job.payload_object.class.should == Delayed::PerformableMethod
job.payload_object.object.should == "AR:Story:#{story.id}"
job.payload_object.object.should == "LOAD;Story;#{story.id}"
job.payload_object.method.should == :tell
job.payload_object.args.should == []
job.payload_object.perform.should == 'Once upon...'
Expand All @@ -91,7 +84,7 @@ def read(story)
job = Delayed::Job.find(:first)
job.payload_object.class.should == Delayed::PerformableMethod
job.payload_object.method.should == :read
job.payload_object.args.should == ["AR:Story:#{story.id}"]
job.payload_object.args.should == ["LOAD;Story;#{story.id}"]
job.payload_object.perform.should == 'Epilog: Once upon...'
end

Expand Down
4 changes: 2 additions & 2 deletions spec/mongo_job_spec.rb
Expand Up @@ -44,7 +44,7 @@ def tell
job = story.send_later(:tell)

job.payload_object.class.should == Delayed::PerformableMethod
job.payload_object.object.should == "MM:MongoStory:#{story.id}"
job.payload_object.object.should == "LOAD;MongoStory;#{story.id}"
job.payload_object.method.should == :tell
job.payload_object.args.should == []
job.payload_object.perform.should == 'Once upon a time…'
Expand All @@ -55,7 +55,7 @@ def tell
job = MongoStoryReader.new.send_later(:read, story)
job.payload_object.class.should == Delayed::PerformableMethod
job.payload_object.method.should == :read
job.payload_object.args.should == ["MM:MongoStory:#{story.id}"]
job.payload_object.args.should == ["LOAD;MongoStory;#{story.id}"]
job.payload_object.perform.should == 'Epilog: Once upon a time…'
end
end
Expand Down

0 comments on commit 35a2808

Please sign in to comment.