mathie-delayed_job 1.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.textile +190 -0
- data/Rakefile +34 -0
- data/VERSION +1 -0
- data/contrib/delayed_job.monitrc +14 -0
- data/generators/delayed_job/delayed_job_generator.rb +22 -0
- data/generators/delayed_job/templates/migration.rb +20 -0
- data/generators/delayed_job/templates/script +5 -0
- data/init.rb +1 -0
- data/lib/delayed/command.rb +90 -0
- data/lib/delayed/job.rb +270 -0
- data/lib/delayed/message_sending.rb +22 -0
- data/lib/delayed/performable_method.rb +55 -0
- data/lib/delayed/recipes.rb +27 -0
- data/lib/delayed/tasks.rb +15 -0
- data/lib/delayed/worker.rb +54 -0
- data/lib/delayed_job.rb +13 -0
- data/mathie-delayed_job.gemspec +67 -0
- data/recipes/delayed_job.rb +1 -0
- data/spec/database.rb +42 -0
- data/spec/delayed_method_spec.rb +150 -0
- data/spec/job_spec.rb +406 -0
- data/spec/story_spec.rb +17 -0
- data/tasks/jobs.rake +1 -0
- metadata +93 -0
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            module Delayed
         | 
| 2 | 
            +
              module MessageSending
         | 
| 3 | 
            +
                def send_later(method, *args)
         | 
| 4 | 
            +
                  Delayed::Job.enqueue Delayed::PerformableMethod.new(self, method.to_sym, args)
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def send_at(time, method, *args)
         | 
| 8 | 
            +
                  Delayed::Job.enqueue(Delayed::PerformableMethod.new(self, method.to_sym, args), 0, time)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                module ClassMethods
         | 
| 12 | 
            +
                  def handle_asynchronously(method)
         | 
| 13 | 
            +
                    aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
         | 
| 14 | 
            +
                    with_method, without_method = "#{aliased_method}_with_send_later#{punctuation}", "#{aliased_method}_without_send_later#{punctuation}"
         | 
| 15 | 
            +
                    define_method(with_method) do |*args|
         | 
| 16 | 
            +
                      send_later(without_method, *args)
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                    alias_method_chain method, :send_later
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end                               
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            module Delayed
         | 
| 2 | 
            +
              class PerformableMethod < Struct.new(:object, :method, :args)
         | 
| 3 | 
            +
                CLASS_STRING_FORMAT = /^CLASS\:([A-Z][\w\:]+)$/
         | 
| 4 | 
            +
                AR_STRING_FORMAT    = /^AR\:([A-Z][\w\:]+)\:(\d+)$/
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                def initialize(object, method, args)
         | 
| 7 | 
            +
                  raise NoMethodError, "undefined method `#{method}' for #{self.inspect}" unless object.respond_to?(method)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  self.object = dump(object)
         | 
| 10 | 
            +
                  self.args   = args.map { |a| dump(a) }
         | 
| 11 | 
            +
                  self.method = method.to_sym
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def display_name  
         | 
| 15 | 
            +
                  case self.object
         | 
| 16 | 
            +
                  when CLASS_STRING_FORMAT then "#{$1}.#{method}"
         | 
| 17 | 
            +
                  when AR_STRING_FORMAT    then "#{$1}##{method}"
         | 
| 18 | 
            +
                  else "Unknown##{method}"
         | 
| 19 | 
            +
                  end      
         | 
| 20 | 
            +
                end    
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def perform
         | 
| 23 | 
            +
                  load(object).send(method, *args.map{|a| load(a)})
         | 
| 24 | 
            +
                rescue ActiveRecord::RecordNotFound
         | 
| 25 | 
            +
                  # We cannot do anything about objects which were deleted in the meantime
         | 
| 26 | 
            +
                  true
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                private
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def load(arg)
         | 
| 32 | 
            +
                  case arg
         | 
| 33 | 
            +
                  when CLASS_STRING_FORMAT then $1.constantize
         | 
| 34 | 
            +
                  when AR_STRING_FORMAT    then $1.constantize.find($2)
         | 
| 35 | 
            +
                  else arg
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def dump(arg)
         | 
| 40 | 
            +
                  case arg
         | 
| 41 | 
            +
                  when Class              then class_to_string(arg)
         | 
| 42 | 
            +
                  when ActiveRecord::Base then ar_to_string(arg)
         | 
| 43 | 
            +
                  else arg
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def ar_to_string(obj)
         | 
| 48 | 
            +
                  "AR:#{obj.class}:#{obj.id}"
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def class_to_string(obj)
         | 
| 52 | 
            +
                  "CLASS:#{obj.name}"
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
| @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # Capistrano Recipes for managing delayed_job
         | 
| 2 | 
            +
            #
         | 
| 3 | 
            +
            # Add these callbacks to have the delayed_job process restart when the server
         | 
| 4 | 
            +
            # is restarted:
         | 
| 5 | 
            +
            #
         | 
| 6 | 
            +
            #   after "deploy:stop",    "delayed_job:stop"
         | 
| 7 | 
            +
            #   after "deploy:start",   "delayed_job:start"
         | 
| 8 | 
            +
            #   after "deploy:restart", "delayed_job:restart"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Capistrano::Configuration.instance.load do
         | 
| 11 | 
            +
              namespace :delayed_job do
         | 
| 12 | 
            +
                desc "Stop the delayed_job process"
         | 
| 13 | 
            +
                task :stop, :roles => :app do
         | 
| 14 | 
            +
                  run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job stop"
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                desc "Start the delayed_job process"
         | 
| 18 | 
            +
                task :start, :roles => :app do
         | 
| 19 | 
            +
                  run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job start"
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                desc "Restart the delayed_job process"
         | 
| 23 | 
            +
                task :restart, :roles => :app do
         | 
| 24 | 
            +
                  run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job restart"
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            # Re-definitions are appended to existing tasks
         | 
| 2 | 
            +
            task :environment
         | 
| 3 | 
            +
            task :merb_env
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            namespace :jobs do
         | 
| 6 | 
            +
              desc "Clear the delayed_job queue."
         | 
| 7 | 
            +
              task :clear => [:merb_env, :environment] do
         | 
| 8 | 
            +
                Delayed::Job.delete_all
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              desc "Start a delayed_job worker."
         | 
| 12 | 
            +
              task :work => [:merb_env, :environment] do
         | 
| 13 | 
            +
                Delayed::Worker.new(:min_priority => ENV['MIN_PRIORITY'], :max_priority => ENV['MAX_PRIORITY']).start
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            module Delayed
         | 
| 2 | 
            +
              class Worker
         | 
| 3 | 
            +
                SLEEP = 5
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                cattr_accessor :logger
         | 
| 6 | 
            +
                self.logger = if defined?(Merb::Logger)
         | 
| 7 | 
            +
                  Merb.logger
         | 
| 8 | 
            +
                elsif defined?(RAILS_DEFAULT_LOGGER)
         | 
| 9 | 
            +
                  RAILS_DEFAULT_LOGGER
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def initialize(options={})
         | 
| 13 | 
            +
                  @quiet = options[:quiet]
         | 
| 14 | 
            +
                  Delayed::Job.min_priority = options[:min_priority] if options.has_key?(:min_priority)
         | 
| 15 | 
            +
                  Delayed::Job.max_priority = options[:max_priority] if options.has_key?(:max_priority)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def start
         | 
| 19 | 
            +
                  say "*** Starting job worker #{Delayed::Job.worker_name}"
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  trap('TERM') { say 'Exiting...'; $exit = true }
         | 
| 22 | 
            +
                  trap('INT')  { say 'Exiting...'; $exit = true }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  loop do
         | 
| 25 | 
            +
                    result = nil
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                    realtime = Benchmark.realtime do
         | 
| 28 | 
            +
                      result = Delayed::Job.work_off
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    count = result.sum
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    break if $exit
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    if count.zero?
         | 
| 36 | 
            +
                      sleep(SLEEP)
         | 
| 37 | 
            +
                    else
         | 
| 38 | 
            +
                      say "#{count} jobs processed at %.4f j/s, %d failed ..." % [count / realtime, result.last]
         | 
| 39 | 
            +
                    end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    break if $exit
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                ensure
         | 
| 45 | 
            +
                  Delayed::Job.clear_locks!
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def say(text)
         | 
| 49 | 
            +
                  puts text unless @quiet
         | 
| 50 | 
            +
                  logger.info text if logger
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
    
        data/lib/delayed_job.rb
    ADDED
    
    | @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            autoload :ActiveRecord, 'activerecord'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require File.dirname(__FILE__) + '/delayed/message_sending'
         | 
| 4 | 
            +
            require File.dirname(__FILE__) + '/delayed/performable_method'
         | 
| 5 | 
            +
            require File.dirname(__FILE__) + '/delayed/job'
         | 
| 6 | 
            +
            require File.dirname(__FILE__) + '/delayed/worker'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Object.send(:include, Delayed::MessageSending)   
         | 
| 9 | 
            +
            Module.send(:include, Delayed::MessageSending::ClassMethods)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            if defined?(Merb::Plugins)
         | 
| 12 | 
            +
              Merb::Plugins.add_rakefiles File.dirname(__FILE__) / 'delayed' / 'tasks'
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,67 @@ | |
| 1 | 
            +
            # Generated by jeweler
         | 
| 2 | 
            +
            # DO NOT EDIT THIS FILE DIRECTLY
         | 
| 3 | 
            +
            # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
         | 
| 4 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |s|
         | 
| 7 | 
            +
              s.name = %q{mathie-delayed_job}
         | 
| 8 | 
            +
              s.version = "1.8.4"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 | 
            +
              s.authors = ["Brandon Keepers", "Tobias L\303\274tke"]
         | 
| 12 | 
            +
              s.date = %q{2010-03-03}
         | 
| 13 | 
            +
              s.description = %q{Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background. It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks.}
         | 
| 14 | 
            +
              s.email = %q{tobi@leetsoft.com}
         | 
| 15 | 
            +
              s.extra_rdoc_files = [
         | 
| 16 | 
            +
                "README.textile"
         | 
| 17 | 
            +
              ]
         | 
| 18 | 
            +
              s.files = [
         | 
| 19 | 
            +
                ".gitignore",
         | 
| 20 | 
            +
                 "MIT-LICENSE",
         | 
| 21 | 
            +
                 "README.textile",
         | 
| 22 | 
            +
                 "Rakefile",
         | 
| 23 | 
            +
                 "VERSION",
         | 
| 24 | 
            +
                 "contrib/delayed_job.monitrc",
         | 
| 25 | 
            +
                 "generators/delayed_job/delayed_job_generator.rb",
         | 
| 26 | 
            +
                 "generators/delayed_job/templates/migration.rb",
         | 
| 27 | 
            +
                 "generators/delayed_job/templates/script",
         | 
| 28 | 
            +
                 "init.rb",
         | 
| 29 | 
            +
                 "lib/delayed/command.rb",
         | 
| 30 | 
            +
                 "lib/delayed/job.rb",
         | 
| 31 | 
            +
                 "lib/delayed/message_sending.rb",
         | 
| 32 | 
            +
                 "lib/delayed/performable_method.rb",
         | 
| 33 | 
            +
                 "lib/delayed/recipes.rb",
         | 
| 34 | 
            +
                 "lib/delayed/tasks.rb",
         | 
| 35 | 
            +
                 "lib/delayed/worker.rb",
         | 
| 36 | 
            +
                 "lib/delayed_job.rb",
         | 
| 37 | 
            +
                 "mathie-delayed_job.gemspec",
         | 
| 38 | 
            +
                 "recipes/delayed_job.rb",
         | 
| 39 | 
            +
                 "spec/database.rb",
         | 
| 40 | 
            +
                 "spec/delayed_method_spec.rb",
         | 
| 41 | 
            +
                 "spec/job_spec.rb",
         | 
| 42 | 
            +
                 "spec/story_spec.rb",
         | 
| 43 | 
            +
                 "tasks/jobs.rake"
         | 
| 44 | 
            +
              ]
         | 
| 45 | 
            +
              s.homepage = %q{http://github.com/mathie/delayed_job}
         | 
| 46 | 
            +
              s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
         | 
| 47 | 
            +
              s.require_paths = ["lib"]
         | 
| 48 | 
            +
              s.rubygems_version = %q{1.3.6}
         | 
| 49 | 
            +
              s.summary = %q{Database-backed asynchronous priority queue system -- Extracted from Shopify}
         | 
| 50 | 
            +
              s.test_files = [
         | 
| 51 | 
            +
                "spec/database.rb",
         | 
| 52 | 
            +
                 "spec/delayed_method_spec.rb",
         | 
| 53 | 
            +
                 "spec/job_spec.rb",
         | 
| 54 | 
            +
                 "spec/story_spec.rb"
         | 
| 55 | 
            +
              ]
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              if s.respond_to? :specification_version then
         | 
| 58 | 
            +
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         | 
| 59 | 
            +
                s.specification_version = 3
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
         | 
| 62 | 
            +
                else
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
              else
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
            end
         | 
| 67 | 
            +
             | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'recipes'))
         | 
    
        data/spec/database.rb
    ADDED
    
    | @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            $:.unshift(File.dirname(__FILE__) + '/../lib')
         | 
| 2 | 
            +
            $:.unshift(File.dirname(__FILE__) + '/../../rspec/lib')
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rubygems'
         | 
| 5 | 
            +
            require 'active_record'
         | 
| 6 | 
            +
            gem 'sqlite3-ruby'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require File.dirname(__FILE__) + '/../init'
         | 
| 9 | 
            +
            require 'spec'
         | 
| 10 | 
            +
              
         | 
| 11 | 
            +
            ActiveRecord::Base.logger = Logger.new('/tmp/dj.log')
         | 
| 12 | 
            +
            ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => '/tmp/jobs.sqlite')
         | 
| 13 | 
            +
            ActiveRecord::Migration.verbose = false
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ActiveRecord::Schema.define do
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              create_table :delayed_jobs, :force => true do |table|
         | 
| 18 | 
            +
                table.integer  :priority, :default => 0
         | 
| 19 | 
            +
                table.integer  :attempts, :default => 0
         | 
| 20 | 
            +
                table.text     :handler
         | 
| 21 | 
            +
                table.string   :last_error
         | 
| 22 | 
            +
                table.datetime :run_at
         | 
| 23 | 
            +
                table.datetime :locked_at
         | 
| 24 | 
            +
                table.string   :locked_by
         | 
| 25 | 
            +
                table.datetime :failed_at
         | 
| 26 | 
            +
                table.timestamps
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              create_table :stories, :force => true do |table|
         | 
| 30 | 
            +
                table.string :text
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| 36 | 
            +
            # Purely useful for test cases...
         | 
| 37 | 
            +
            class Story < ActiveRecord::Base
         | 
| 38 | 
            +
              def tell; text; end       
         | 
| 39 | 
            +
              def whatever(n, _); tell*n; end
         | 
| 40 | 
            +
              
         | 
| 41 | 
            +
              handle_asynchronously :whatever
         | 
| 42 | 
            +
            end
         | 
| @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/database'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class SimpleJob
         | 
| 4 | 
            +
              cattr_accessor :runs; self.runs = 0
         | 
| 5 | 
            +
              def perform; @@runs += 1; end
         | 
| 6 | 
            +
            end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class RandomRubyObject  
         | 
| 9 | 
            +
              def say_hello
         | 
| 10 | 
            +
                'hello'
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            class ErrorObject
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def throw
         | 
| 17 | 
            +
                raise ActiveRecord::RecordNotFound, '...'
         | 
| 18 | 
            +
                false
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            class StoryReader
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def read(story)
         | 
| 26 | 
            +
                "Epilog: #{story.tell}"
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            class StoryReader
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def read(story)
         | 
| 34 | 
            +
                "Epilog: #{story.tell}"
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            describe 'random ruby objects' do
         | 
| 40 | 
            +
              before       { Delayed::Job.delete_all }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              it "should respond_to :send_later method" do
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                RandomRubyObject.new.respond_to?(:send_later)
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              it "should raise a ArgumentError if send_later is called but the target method doesn't exist" do
         | 
| 49 | 
            +
                lambda { RandomRubyObject.new.send_later(:method_that_deos_not_exist) }.should raise_error(NoMethodError)
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              it "should add a new entry to the job table when send_later is called on it" do
         | 
| 53 | 
            +
                Delayed::Job.count.should == 0
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                RandomRubyObject.new.send_later(:to_s)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                Delayed::Job.count.should == 1
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              it "should add a new entry to the job table when send_later is called on the class" do
         | 
| 61 | 
            +
                Delayed::Job.count.should == 0
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                RandomRubyObject.send_later(:to_s)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                Delayed::Job.count.should == 1
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              it "should run get the original method executed when the job is performed" do
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                RandomRubyObject.new.send_later(:say_hello)
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                Delayed::Job.count.should == 1
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              it "should ignore ActiveRecord::RecordNotFound errors because they are permanent" do
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                ErrorObject.new.send_later(:throw)
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                Delayed::Job.count.should == 1
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                Delayed::Job.reserve_and_run_one_job
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                Delayed::Job.count.should == 0
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              it "should store the object as string if its an active record" do
         | 
| 88 | 
            +
                story = Story.create :text => 'Once upon...'
         | 
| 89 | 
            +
                story.send_later(:tell)
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                job =  Delayed::Job.find(:first)
         | 
| 92 | 
            +
                job.payload_object.class.should   == Delayed::PerformableMethod
         | 
| 93 | 
            +
                job.payload_object.object.should  == "AR:Story:#{story.id}"
         | 
| 94 | 
            +
                job.payload_object.method.should  == :tell
         | 
| 95 | 
            +
                job.payload_object.args.should    == []
         | 
| 96 | 
            +
                job.payload_object.perform.should == 'Once upon...'
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              it "should store arguments as string if they an active record" do
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                story = Story.create :text => 'Once upon...'
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                reader = StoryReader.new
         | 
| 104 | 
            +
                reader.send_later(:read, story)
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                job =  Delayed::Job.find(:first)
         | 
| 107 | 
            +
                job.payload_object.class.should   == Delayed::PerformableMethod
         | 
| 108 | 
            +
                job.payload_object.method.should  == :read
         | 
| 109 | 
            +
                job.payload_object.args.should    == ["AR:Story:#{story.id}"]
         | 
| 110 | 
            +
                job.payload_object.perform.should == 'Epilog: Once upon...'
         | 
| 111 | 
            +
              end                 
         | 
| 112 | 
            +
              
         | 
| 113 | 
            +
              it "should call send later on methods which are wrapped with handle_asynchronously" do
         | 
| 114 | 
            +
                story = Story.create :text => 'Once upon...'
         | 
| 115 | 
            +
              
         | 
| 116 | 
            +
                Delayed::Job.count.should == 0
         | 
| 117 | 
            +
              
         | 
| 118 | 
            +
                story.whatever(1, 5)
         | 
| 119 | 
            +
              
         | 
| 120 | 
            +
                Delayed::Job.count.should == 1
         | 
| 121 | 
            +
                job =  Delayed::Job.find(:first)
         | 
| 122 | 
            +
                job.payload_object.class.should   == Delayed::PerformableMethod
         | 
| 123 | 
            +
                job.payload_object.method.should  == :whatever_without_send_later
         | 
| 124 | 
            +
                job.payload_object.args.should    == [1, 5]
         | 
| 125 | 
            +
                job.payload_object.perform.should == 'Once upon...'
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              context "send_at" do
         | 
| 129 | 
            +
                it "should queue a new job" do
         | 
| 130 | 
            +
                  lambda do
         | 
| 131 | 
            +
                    "string".send_at(1.hour.from_now, :length)
         | 
| 132 | 
            +
                  end.should change { Delayed::Job.count }.by(1)
         | 
| 133 | 
            +
                end
         | 
| 134 | 
            +
                
         | 
| 135 | 
            +
                it "should schedule the job in the future" do
         | 
| 136 | 
            +
                  time = 1.hour.from_now
         | 
| 137 | 
            +
                  job = "string".send_at(time, :length)
         | 
| 138 | 
            +
                  job.run_at.should == time
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
                
         | 
| 141 | 
            +
                it "should store payload as PerformableMethod" do
         | 
| 142 | 
            +
                  job = "string".send_at(1.hour.from_now, :count, 'r')
         | 
| 143 | 
            +
                  job.payload_object.class.should   == Delayed::PerformableMethod
         | 
| 144 | 
            +
                  job.payload_object.method.should  == :count
         | 
| 145 | 
            +
                  job.payload_object.args.should    == ['r']
         | 
| 146 | 
            +
                  job.payload_object.perform.should == 1
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
              end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
            end
         |