Skip to content

Instantly share code, notes, and snippets.

@devdatta
Created March 24, 2010 13:05
Show Gist options
  • Select an option

  • Save devdatta/342259 to your computer and use it in GitHub Desktop.

Select an option

Save devdatta/342259 to your computer and use it in GitHub Desktop.
module Resque
##
# Resque StateMachine
#
# Is a Mash to be used in a resque queue. The create method will
# initiate the object and enqueue it.
#
# Can pass in a run_at attribute to delay the run.
# Can pass in a test_mode attribute to force test mode.
#
# Class method of retry_delay is responsible for delaying retry attempts.
#
# Class method of max_attempts is used to determine the maximum number
# of attempts before marking a message as failed.
#
# Class method of queue is used to set the resque queue that this job
# belongs in
#
# Class method of test_mode is used to determine what method is run during
# processing. If in test_mode, the run_test method is called. Otherwise,
# the run method is called.
class StateMachine < Hashie::Mash
##
# Perform the job in the Resque Worker
def self.perform(job)
new(job).process
end
##
# Create and enqueue job
def self.create(params=nil)
new(params).enqueue
end
##
# Is this in test_mode mode?
def self.test_mode
@test_mode ||= false
end
##
# Set the test_mode mode
def self.test_mode=(mode)
@test_mode = mode
end
##
# Get the max attempts
def self.max_attempts
@max_attempts ||= 1
end
##
# Set the max attempts
def self.max_attempts=(number)
@max_attempts = number
end
##
# Get the retry delay
def self.retry_delay
@retry_delay ||= 0
end
##
# Set the retry delay
def self.retry_delay=(seconds)
@retry_delay = seconds
end
##
# Get the queue for the instance
def self.queue
@queue ||= :default
end
##
# Set the queue for the instance
def self.queue=(queue)
@queue = queue
end
##
# Send the object to the Resque queue
def enqueue
if run_at.is_a?(Time) && (run_at > Time.now)
Resque.enqueue_at(run_at, self.class, self)
else
Resque.enqueue(self.class, self)
end
end
##
# Requeue the job to Resque
def requeue
if self.class.retry_delay > 0
Resque.enqueue_in(self.class.retry_delay, self.class, self)
else
Resque.enqueue(self.class, self)
end
end
##
# Is the job in test_mode mode?
def test_mode?
test_mode || self.class.test_mode
end
##
# Run test_mode should be overridden in sub-class
def run_test
true
end
##
# Run should be overriden in sub-class
def run
true
end
##
# Handle failure should be overriden in sub-class
def fail
true
end
##
# Process the job.
#
# Increment the number of attempts.
def process
self.attempts ||= 0
self.attempts += 1
self.status = "success"
begin
test_mode? ? run_test : run
rescue StandardError => error
self.status = "failure"
self.error = error.message
if (attempts >= self.class.max_attempts)
fail
raise
end
requeue
end
end
end
end
class EmailJob < Resque::StateMachine
self.queue = :email
self.max_attempts = 10
self.retry_delay = 60
self.test_mode = false
##
# Run Job
#
# Send Email message and save to database if successful
def run
validate
deliver
record
end
##
# Run job in test_mode
def run_test
validate
self.test_mode = true
record
end
def mail
mail = Mail.new
mail.to = self.to
mail.from = self.from
mail.subject = self.subject
unless self.text.blank?
text_part = Mail::Part.new
text_part.body = self.text
mail.text_part = text_part
end
unless self.html.blank?
html_part = Mail::Part.new
html_part.content_type = 'text/html; charset=UTF-8'
html_part.body = self.html
mail.html_part = html_part
end
mail
end
protected
##
# Make sure required fields are present
def validate
unless to && from && subject && (text || html)
raise(StandardError, "Invalid Email Message")
end
end
##
# Send Email to relay
def deliver
unless self.response = mail.deliver!
raise(StandardError, "Email not delivered")
end
end
##
# Record the delivery in the database. Use straight ruby driver
# for speed
def record
email = self.dup
Email.insert({
:text => email.delete('text'),
:html => email.delete('html'),
:subject => email.delete('subject'),
:from => email.delete('from'),
:to => email.delete('to'),
:status => email.delete('status'),
:error => email.delete('error'),
:response => email.delete('response'),
:test_mode => sms.delete('test_mode'),
:meta => email.to_hash
}) || raise(StandardError, "Email sent but not recorded")
end
##
# Record the failure in the database
def fail
record
end
end
__END__
Examples:
EmailJob.create(:to => 'someone', :from => 'me', :subject => 'hi', :text => 'hello')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment