blaxter-delayed_job 1.7.0 → 1.7.99

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/README.textile CHANGED
@@ -1,6 +1,6 @@
1
1
  h1. Delayed::Job
2
2
 
3
- Delated_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.
3
+ Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.
4
4
 
5
5
  It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks. Amongst those tasks are:
6
6
 
@@ -15,39 +15,43 @@ It is a direct extraction from Shopify where the job table is responsible for a
15
15
  h2. Setup
16
16
 
17
17
  The library evolves around a delayed_jobs table which looks as follows:
18
-
19
- create_table :delayed_jobs, :force => true do |table|
18
+ <pre><code>create_table :delayed_jobs, :force => true do |table|
20
19
  table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
21
20
  table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
22
21
  table.text :handler # YAML-encoded string of the object that will do work
22
+ table.string :job_type # Class name of the job object, for type-specific workers
23
23
  table.string :last_error # reason for last failure (See Note below)
24
24
  table.datetime :run_at # When to run. Could be Time.now for immediately, or sometime in the future.
25
25
  table.datetime :locked_at # Set when a client is working on this object
26
26
  table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
27
27
  table.string :locked_by # Who is working on this object (if locked)
28
+ table.datetime :finished_at # Used for statiscics / monitoring
28
29
  table.timestamps
29
30
  end
30
-
31
+ </code></pre>
31
32
  On failure, the job is scheduled again in 5 seconds + N ** 4, where N is the number of retries.
32
33
 
33
- The default MAX_ATTEMPTS is 25. After this, the job either deleted (default), or left in the database with "failed_at" set.
34
- With the default of 25 attempts, the last retry will be 20 days later, with the last interval being almost 100 hours.
34
+ The default MAX_ATTEMPTS is 25- jobs can override this value by responding to :max_attempts. After this, the job
35
+ either deleted (default), or left in the database with "failed_at" set. With the default of 25 attempts,
36
+ the last retry will be 20 days later, with the last interval being almost 100 hours.
35
37
 
36
38
  The default MAX_RUN_TIME is 4.hours. If your job takes longer than that, another computer could pick it up. It's up to you to
37
39
  make sure your job doesn't exceed this time. You should set this to the longest time you think the job could take.
38
40
 
39
- By default, it will delete failed jobs (and it always deletes successful jobs). If you want to keep failed jobs, set
40
- Delayed::Job.destroy_failed_jobs = false. The failed jobs will be marked with non-null failed_at.
41
+ By default, it will delete failed jobs. If you want to keep failed jobs, set
42
+ @Delayed::Job.destroy_failed_jobs = false@. The failed jobs will be marked with non-null failed_at.
41
43
 
42
- Here is an example of changing job parameters in Rails:
44
+ Same thing for successful jobs. They're deleted by default and, to keep them, set @Delayed::Job.destroy_successful_jobs = false@. They will be marked with finished_at. This is useful for gathering statistics like how long jobs took between entering the queue (created_at) and being finished (finished_at).
43
45
 
44
- # config/initializers/delayed_job_config.rb
46
+ Here is an example of changing job parameters in Rails:
47
+ <pre><code># config/initializers/delayed_job_config.rb
45
48
  Delayed::Job.destroy_failed_jobs = false
49
+ Delayed::Job.destroy_successful_jobs = false
46
50
  silence_warnings do
47
51
  Delayed::Job.const_set("MAX_ATTEMPTS", 3)
48
52
  Delayed::Job.const_set("MAX_RUN_TIME", 5.minutes)
49
53
  end
50
-
54
+ </code></pre>
51
55
  Note: If your error messages are long, consider changing last_error field to a :text instead of a :string (255 character limit).
52
56
 
53
57
 
@@ -55,20 +59,18 @@ h2. Usage
55
59
 
56
60
  Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table.
57
61
  Job objects are serialized to yaml so that they can later be resurrected by the job runner.
58
-
59
- class NewsletterJob < Struct.new(:text, :emails)
62
+ <pre><code>class NewsletterJob < Struct.new(:text, :emails)
60
63
  def perform
61
64
  emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
62
65
  end
63
66
  end
64
67
 
65
68
  Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
66
-
69
+ </code></pre>
67
70
  There is also a second way to get jobs in the queue: send_later.
68
71
 
69
-
70
- BatchImporter.new(Shop.find(1)).send_later(:import_massive_csv, massive_csv)
71
-
72
+ <pre><code>BatchImporter.new(Shop.find(1)).send_later(:import_massive_csv, massive_csv)
73
+ </code></pre>
72
74
 
73
75
  This will simply create a Delayed::PerformableMethod job in the jobs table which serializes all the parameters you pass to it. There are some special smarts for active record objects
74
76
  which are stored as their text representation and loaded from the database fresh when the job is actually run later.
@@ -80,8 +82,7 @@ You can invoke @rake jobs:work@ which will start working off jobs. You can cance
80
82
 
81
83
  You can also run by writing a simple @script/job_runner@, and invoking it externally:
82
84
 
83
- <pre><code>
84
- #!/usr/bin/env ruby
85
+ <pre><code>#!/usr/bin/env ruby
85
86
  require File.dirname(__FILE__) + '/../config/environment'
86
87
 
87
88
  Delayed::Worker.new.start
@@ -93,6 +94,13 @@ Keep in mind that each worker will check the database at least every 5 seconds.
93
94
 
94
95
  Note: The rake task will exit if the database has any network connectivity problems.
95
96
 
97
+ If you only want to run specific types of jobs in a given worker, include them when initializing the worker:
98
+
99
+ <pre><code>
100
+ Delayed::Worker.new(:job_types => "SimpleJob").start
101
+ Delayed::Worker.new(:job_types => ["SimpleJob", "NewsletterJob"]).start
102
+ </pre></code>
103
+
96
104
  h3. Cleaning up
97
105
 
98
106
  You can invoke @rake jobs:clear@ to delete all jobs in the queue.
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ begin
3
+ require 'jeweler'
4
+
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "delayed_job"
7
+ s.summary = "Database-backed asynchronous priority queue system -- Extracted from Shopify"
8
+ s.email = "tobi@leetsoft.com"
9
+ s.homepage = "http://github.com/tobi/delayed_job/tree/master"
10
+ s.description = "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."
11
+ s.authors = ["Tobias Lütke"]
12
+
13
+ s.has_rdoc = true
14
+ s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
15
+ s.extra_rdoc_files = ["README.textile"]
16
+
17
+ s.test_files = Dir['spec/**/*']
18
+ end
19
+
20
+ rescue LoadError
21
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
22
+ exit 1
23
+ end
24
+
25
+ require 'spec/rake/spectask'
26
+ Spec::Rake::SpecTask.new(:spec) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
30
+
31
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
32
+ spec.libs << 'lib' << 'spec'
33
+ spec.pattern = 'spec/**/*_spec.rb'
34
+ spec.rcov = true
35
+ end
36
+
37
+
38
+ task :default => :spec
data/delayed_job.gemspec CHANGED
@@ -1,41 +1,57 @@
1
- #version = File.read('README.textile').scan(/^\*\s+([\d\.]+)/).flatten
1
+ # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = "delayed_job"
5
- s.version = "1.7.0"
6
- s.date = "2008-11-28"
7
- s.summary = "Database-backed asynchronous priority queue system -- Extracted from Shopify"
8
- s.email = "tobi@leetsoft.com"
9
- s.homepage = "http://github.com/tobi/delayed_job/tree/master"
10
- s.description = "Delated_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."
11
- s.authors = ["Tobias Lütke"]
4
+ s.name = %q{delayed_job}
5
+ s.version = "1.7.99"
12
6
 
13
- # s.bindir = "bin"
14
- # s.executables = ["delayed_job"]
15
- # s.default_executable = "delayed_job"
16
-
17
- s.has_rdoc = false
18
- s.rdoc_options = ["--main", "README.textile"]
19
- s.extra_rdoc_files = ["README.textile"]
20
-
21
- # run git ls-files to get an updated list
22
- s.files = %w[
23
- MIT-LICENSE
24
- README.textile
25
- delayed_job.gemspec
26
- init.rb
27
- lib/delayed/job.rb
28
- lib/delayed/message_sending.rb
29
- lib/delayed/performable_method.rb
30
- lib/delayed/worker.rb
31
- lib/delayed_job.rb
32
- tasks/jobs.rake
33
- tasks/tasks.rb
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Tobias L\303\274tke"]
9
+ s.date = %q{2009-08-06}
10
+ 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.}
11
+ s.email = %q{tobi@leetsoft.com}
12
+ s.extra_rdoc_files = [
13
+ "README.textile"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "MIT-LICENSE",
18
+ "README.textile",
19
+ "Rakefile",
20
+ "delayed_job.gemspec",
21
+ "generators/delayed_job/delayed_job_generator.rb",
22
+ "generators/delayed_job/templates/migration.rb",
23
+ "init.rb",
24
+ "lib/delayed/job.rb",
25
+ "lib/delayed/message_sending.rb",
26
+ "lib/delayed/performable_method.rb",
27
+ "lib/delayed/worker.rb",
28
+ "lib/delayed_job.rb",
29
+ "spec/database.rb",
30
+ "spec/delayed_method_spec.rb",
31
+ "spec/job_spec.rb",
32
+ "spec/story_spec.rb",
33
+ "tasks/jobs.rake",
34
+ "tasks/tasks.rb"
34
35
  ]
35
- s.test_files = %w[
36
- spec/database.rb
37
- spec/delayed_method_spec.rb
38
- spec/job_spec.rb
39
- spec/story_spec.rb
36
+ s.homepage = %q{http://github.com/tobi/delayed_job/tree/master}
37
+ s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.3}
40
+ s.summary = %q{Database-backed asynchronous priority queue system -- Extracted from Shopify}
41
+ s.test_files = [
42
+ "spec/delayed_method_spec.rb",
43
+ "spec/story_spec.rb",
44
+ "spec/database.rb",
45
+ "spec/job_spec.rb"
40
46
  ]
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
+ else
54
+ end
55
+ else
56
+ end
41
57
  end
@@ -0,0 +1,11 @@
1
+ class DelayedJobGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ m.migration_template 'migration.rb', 'db/migrate',
5
+ :assigns => { :migration_name => 'CreateDelayedJobs' },
6
+ :migration_file_name => "create_delayed_jobs"
7
+ end
8
+ end
9
+
10
+ end
11
+
@@ -0,0 +1,21 @@
1
+ class CreateDelayedJobs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :delayed_jobs do |t|
4
+ t.integer :priority, :default => 0
5
+ t.integer :attempts, :default => 0
6
+ t.text :handler
7
+ t.string :job_type
8
+ t.string :last_error
9
+ t.datetime :run_at
10
+ t.datetime :locked_at
11
+ t.datetime :failed_at
12
+ t.string :locked_by
13
+ t.datetime :finished_at
14
+ t.timestamps
15
+ end
16
+ end
17
+
18
+ def self.down
19
+ drop_table :delayed_jobs
20
+ end
21
+ end
data/lib/delayed/job.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'timeout'
2
+
1
3
  module Delayed
2
4
 
3
5
  class DeserializationError < StandardError
@@ -16,20 +18,27 @@ module Delayed
16
18
  cattr_accessor :destroy_failed_jobs
17
19
  self.destroy_failed_jobs = true
18
20
 
21
+ # By default successful jobs are destroyed after finished.
22
+ # If you want to keep them around (for statistics/monitoring),
23
+ # set this to false.
24
+ cattr_accessor :destroy_successful_jobs
25
+ self.destroy_successful_jobs = true
26
+
19
27
  # Every worker has a unique name which by default is the pid of the process.
20
28
  # There are some advantages to overriding this with something which survives worker retarts:
21
29
  # Workers can safely resume working on tasks which are locked by themselves. The worker will assume that it crashed before.
22
30
  cattr_accessor :worker_name
23
31
  self.worker_name = "host:#{Socket.gethostname} pid:#{Process.pid}" rescue "pid:#{Process.pid}"
24
32
 
25
- NextTaskSQL = '(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR (locked_by = ?)) AND failed_at IS NULL'
33
+ NextTaskSQL = '(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR (locked_by = ?)) AND failed_at IS NULL AND finished_at IS NULL'
26
34
  NextTaskOrder = 'priority DESC, run_at ASC'
27
35
 
28
36
  ParseObjectFromYaml = /\!ruby\/\w+\:([^\s]+)/
29
37
 
30
- cattr_accessor :min_priority, :max_priority
38
+ cattr_accessor :min_priority, :max_priority, :job_types
31
39
  self.min_priority = nil
32
40
  self.max_priority = nil
41
+ self.job_types = nil
33
42
 
34
43
  # When a worker is exiting, make sure we don't have any locked jobs.
35
44
  def self.clear_locks!
@@ -57,13 +66,14 @@ module Delayed
57
66
  end
58
67
 
59
68
  def payload_object=(object)
60
- self['handler'] = object.to_yaml
69
+ self['job_type'] = object.class.to_s
70
+ self['handler'] = object.to_yaml
61
71
  end
62
72
 
63
73
  # Reschedule the job in the future (when a job fails).
64
74
  # Uses an exponential scale depending on the number of failed attempts.
65
75
  def reschedule(message, backtrace = [], time = nil)
66
- if self.attempts < MAX_ATTEMPTS
76
+ if self.attempts < (payload_object.send(:max_attempts) rescue MAX_ATTEMPTS)
67
77
  time ||= Job.db_time_now + (attempts ** 4) + 5
68
78
 
69
79
  self.attempts += 1
@@ -89,11 +99,11 @@ module Delayed
89
99
 
90
100
  begin
91
101
  runtime = Benchmark.realtime do
92
- invoke_job # TODO: raise error if takes longer than max_run_time
93
- destroy
102
+ Timeout.timeout(max_run_time.to_i) { invoke_job }
94
103
  end
95
- # TODO: warn if runtime > max_run_time ?
96
- Delayed::Worker.logger.info "* [JOB] #{name} completed after %.4f" % runtime
104
+ destroy_successful_jobs ? destroy :
105
+ update_attribute(:finished_at, Time.now)
106
+ Delayed::Worker.logger.info "* [JOB] #{name} completed after %.4f" % runtime
97
107
  return true # did work
98
108
  rescue Exception => e
99
109
  reschedule e.message, e.backtrace
@@ -136,6 +146,11 @@ module Delayed
136
146
  conditions << max_priority
137
147
  end
138
148
 
149
+ if self.job_types
150
+ sql << ' AND (job_type IN (?))'
151
+ conditions << job_types
152
+ end
153
+
139
154
  conditions.unshift(sql)
140
155
 
141
156
  records = ActiveRecord::Base.silence do
@@ -13,6 +13,7 @@ module Delayed
13
13
  @quiet = options[:quiet]
14
14
  Delayed::Job.min_priority = options[:min_priority] if options.has_key?(:min_priority)
15
15
  Delayed::Job.max_priority = options[:max_priority] if options.has_key?(:max_priority)
16
+ Delayed::Job.job_types = options[:job_types] if options.has_key?(:job_types)
16
17
  end
17
18
 
18
19
  def start
data/spec/database.rb CHANGED
@@ -3,13 +3,17 @@ $:.unshift(File.dirname(__FILE__) + '/../../rspec/lib')
3
3
 
4
4
  require 'rubygems'
5
5
  require 'active_record'
6
- gem 'sqlite3-ruby'
7
6
 
8
7
  require File.dirname(__FILE__) + '/../init'
9
8
  require 'spec'
10
-
11
- ActiveRecord::Base.logger = Logger.new('/tmp/dj.log')
12
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => '/tmp/jobs.sqlite')
9
+
10
+ logger = Logger.new('/tmp/dj.log')
11
+ ActiveRecord::Base.logger = logger
12
+ Delayed::Worker.logger = logger
13
+ ActiveRecord::Base.establish_connection(
14
+ :adapter => (PLATFORM =~ /java/ ? 'jdbcsqlite3' : 'sqlite3'),
15
+ :database => '/tmp/jobs.sqlite'
16
+ )
13
17
  ActiveRecord::Migration.verbose = false
14
18
 
15
19
  ActiveRecord::Schema.define do
@@ -18,11 +22,13 @@ ActiveRecord::Schema.define do
18
22
  table.integer :priority, :default => 0
19
23
  table.integer :attempts, :default => 0
20
24
  table.text :handler
25
+ table.string :job_type
21
26
  table.string :last_error
22
27
  table.datetime :run_at
23
28
  table.datetime :locked_at
24
29
  table.string :locked_by
25
30
  table.datetime :failed_at
31
+ table.datetime :finished_at
26
32
  table.timestamps
27
33
  end
28
34
 
@@ -35,8 +41,8 @@ end
35
41
 
36
42
  # Purely useful for test cases...
37
43
  class Story < ActiveRecord::Base
38
- def tell; text; end
44
+ def tell; text; end
39
45
  def whatever(n, _); tell*n; end
40
-
46
+
41
47
  handle_asynchronously :whatever
42
48
  end
data/spec/job_spec.rb CHANGED
@@ -5,11 +5,19 @@ class SimpleJob
5
5
  def perform; @@runs += 1; end
6
6
  end
7
7
 
8
+ class CustomJob < SimpleJob
9
+ def max_attempts; 3; end
10
+ end
11
+
8
12
  class ErrorJob
9
13
  cattr_accessor :runs; self.runs = 0
10
14
  def perform; raise 'did not work'; end
11
15
  end
12
16
 
17
+ class LongRunningJob
18
+ def perform; sleep 250; end
19
+ end
20
+
13
21
  module M
14
22
  class ModuleJob
15
23
  cattr_accessor :runs; self.runs = 0
@@ -69,8 +77,43 @@ describe Delayed::Job do
69
77
 
70
78
  SimpleJob.runs.should == 1
71
79
  end
72
-
73
-
80
+
81
+ it "should work on specified job types" do
82
+ SimpleJob.runs.should == 0
83
+
84
+ Delayed::Job.job_types = "SimpleJob"
85
+ Delayed::Job.enqueue SimpleJob.new
86
+ Delayed::Job.work_off
87
+
88
+ SimpleJob.runs.should == 1
89
+
90
+ Delayed::Job.job_types = nil
91
+ end
92
+
93
+ it "should not work on unspecified job types" do
94
+ SimpleJob.runs.should == 0
95
+
96
+ Delayed::Job.job_types = "AnotherJob"
97
+ Delayed::Job.enqueue SimpleJob.new
98
+ Delayed::Job.work_off
99
+
100
+ SimpleJob.runs.should == 0
101
+
102
+ Delayed::Job.job_types = nil
103
+ end
104
+
105
+ it "should work on specified job types even when it's a list" do
106
+ SimpleJob.runs.should == 0
107
+
108
+ Delayed::Job.job_types = %w( Whatever SimpleJob )
109
+ Delayed::Job.enqueue SimpleJob.new
110
+ Delayed::Job.work_off
111
+
112
+ SimpleJob.runs.should == 1
113
+
114
+ Delayed::Job.job_types = nil
115
+ end
116
+
74
117
  it "should work with eval jobs" do
75
118
  $eval_job_ran = false
76
119
 
@@ -92,7 +135,49 @@ describe Delayed::Job do
92
135
 
93
136
  M::ModuleJob.runs.should == 1
94
137
  end
95
-
138
+
139
+ it "should be destroyed if it succeeded and we want to destroy jobs" do
140
+ default = Delayed::Job.destroy_successful_jobs
141
+ Delayed::Job.destroy_successful_jobs = true
142
+
143
+ Delayed::Job.enqueue SimpleJob.new
144
+ Delayed::Job.work_off
145
+
146
+ Delayed::Job.count.should == 0
147
+
148
+ Delayed::Job.destroy_successful_jobs = default
149
+ end
150
+
151
+ it "should be kept if it succeeded and we don't want to destroy jobs" do
152
+ default = Delayed::Job.destroy_successful_jobs
153
+ Delayed::Job.destroy_successful_jobs = false
154
+
155
+ Delayed::Job.enqueue SimpleJob.new
156
+ Delayed::Job.work_off
157
+
158
+ Delayed::Job.count.should == 1
159
+
160
+ Delayed::Job.destroy_successful_jobs = default
161
+ end
162
+
163
+ it "should be finished if it succeeded and we don't want to destroy jobs" do
164
+ default = Delayed::Job.destroy_successful_jobs
165
+ Delayed::Job.destroy_successful_jobs = false
166
+ @job = Delayed::Job.create :payload_object => SimpleJob.new
167
+
168
+ @job.reload.finished_at.should == nil
169
+ Delayed::Job.work_off
170
+ @job.reload.finished_at.should_not == nil
171
+
172
+ Delayed::Job.destroy_successful_jobs = default
173
+ end
174
+
175
+ it "should never find finished jobs" do
176
+ @job = Delayed::Job.create :payload_object => SimpleJob.new,
177
+ :finished_at => Time.now
178
+ Delayed::Job.find_available(1).length.should == 0
179
+ end
180
+
96
181
  it "should re-schedule by about 1 second at first and increment this more and more minutes when it fails to execute properly" do
97
182
  Delayed::Job.enqueue ErrorJob.new
98
183
  Delayed::Job.work_off(1)
@@ -100,7 +185,7 @@ describe Delayed::Job do
100
185
  job = Delayed::Job.find(:first)
101
186
 
102
187
  job.last_error.should =~ /did not work/
103
- job.last_error.should =~ /job_spec.rb:10:in `perform'/
188
+ job.last_error.should =~ /job_spec.rb:14:in `perform'/
104
189
  job.attempts.should == 1
105
190
 
106
191
  job.run_at.should > Delayed::Job.db_time_now - 10.minutes
@@ -171,6 +256,24 @@ describe Delayed::Job do
171
256
  Delayed::Job.destroy_failed_jobs = default
172
257
  end
173
258
 
259
+ it "should allow jobs to override max_attemps and behave appropriately" do
260
+ default = Delayed::Job.destroy_failed_jobs
261
+ Delayed::Job.destroy_failed_jobs = true
262
+
263
+ @job = Delayed::Job.create :payload_object => CustomJob.new, :attempts => 5
264
+ @job.should_receive(:destroy)
265
+ @job.reschedule 'FAIL'
266
+
267
+ Delayed::Job.destroy_failed_jobs = default
268
+ end
269
+
270
+ it "should fail after MAX_RUN_TIME" do
271
+ @job = Delayed::Job.create :payload_object => LongRunningJob.new
272
+ Delayed::Job.reserve_and_run_one_job(1.second)
273
+ @job.reload.last_error.should =~ /expired/
274
+ @job.attempts.should == 1
275
+ end
276
+
174
277
  it "should never find failed jobs" do
175
278
  @job = Delayed::Job.create :payload_object => SimpleJob.new, :attempts => 50, :failed_at => Time.now
176
279
  Delayed::Job.find_available(1).length.should == 0
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blaxter-delayed_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 1.7.99
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Tobias L\xC3\xBCtke"
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-28 00:00:00 -08:00
12
+ date: 2009-08-06 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: Delated_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.
16
+ description: 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.
17
17
  email: tobi@leetsoft.com
18
18
  executables: []
19
19
 
@@ -22,15 +22,23 @@ extensions: []
22
22
  extra_rdoc_files:
23
23
  - README.textile
24
24
  files:
25
+ - .gitignore
25
26
  - MIT-LICENSE
26
27
  - README.textile
28
+ - Rakefile
27
29
  - delayed_job.gemspec
30
+ - generators/delayed_job/delayed_job_generator.rb
31
+ - generators/delayed_job/templates/migration.rb
28
32
  - init.rb
29
33
  - lib/delayed/job.rb
30
34
  - lib/delayed/message_sending.rb
31
35
  - lib/delayed/performable_method.rb
32
36
  - lib/delayed/worker.rb
33
37
  - lib/delayed_job.rb
38
+ - spec/database.rb
39
+ - spec/delayed_method_spec.rb
40
+ - spec/job_spec.rb
41
+ - spec/story_spec.rb
34
42
  - tasks/jobs.rake
35
43
  - tasks/tasks.rb
36
44
  has_rdoc: false
@@ -40,6 +48,8 @@ post_install_message:
40
48
  rdoc_options:
41
49
  - --main
42
50
  - README.textile
51
+ - --inline-source
52
+ - --line-numbers
43
53
  require_paths:
44
54
  - lib
45
55
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -59,10 +69,10 @@ requirements: []
59
69
  rubyforge_project:
60
70
  rubygems_version: 1.3.5
61
71
  signing_key:
62
- specification_version: 2
72
+ specification_version: 3
63
73
  summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
64
74
  test_files:
65
- - spec/database.rb
66
75
  - spec/delayed_method_spec.rb
67
- - spec/job_spec.rb
68
76
  - spec/story_spec.rb
77
+ - spec/database.rb
78
+ - spec/job_spec.rb