Created
March 24, 2010 13:05
-
-
Save devdatta/342259 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 | |
| ## | |
| # 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 | |
| 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