delayed_job 2.1.2 → 2.1.3

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.
@@ -206,6 +206,8 @@ Delayed::Worker.destroy_failed_jobs = false. The failed jobs will be marked with
206
206
 
207
207
  By default all jobs are scheduled with priority = 0, which is top priority. You can change this by setting Delayed::Worker.default_priority to something else. Lower numbers have higher priority.
208
208
 
209
+ It is possible to disable delayed jobs for testing purposes. Set Delayed::Worker.delay_jobs = false to execute all jobs realtime.
210
+
209
211
  Here is an example of changing job parameters in Rails:
210
212
 
211
213
  <pre>
@@ -214,6 +216,7 @@ Delayed::Worker.destroy_failed_jobs = false
214
216
  Delayed::Worker.sleep_delay = 60
215
217
  Delayed::Worker.max_attempts = 3
216
218
  Delayed::Worker.max_run_time = 5.minutes
219
+ Delayed::Worker.delay_jobs = !Rails.env.test?
217
220
  </pre>
218
221
 
219
222
  h3. Cleaning up
@@ -16,10 +16,6 @@ module Delayed
16
16
  }
17
17
  scope :by_priority, order('priority ASC, run_at ASC')
18
18
 
19
- scope :locked_by_worker, lambda{|worker_name, max_run_time|
20
- where(['locked_by = ? AND locked_at > ?', worker_name, db_time_now - max_run_time])
21
- }
22
-
23
19
  def self.before_fork
24
20
  ::ActiveRecord::Base.clear_all_connections!
25
21
  end
@@ -33,25 +29,37 @@ module Delayed
33
29
  update_all("locked_by = null, locked_at = null", ["locked_by = ?", worker_name])
34
30
  end
35
31
 
36
- def self.jobs_available_to_worker(worker_name, max_run_time)
32
+ # Find a few candidate jobs to run (in case some immediately get locked by others).
33
+ def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
37
34
  scope = self.ready_to_run(worker_name, max_run_time)
38
35
  scope = scope.scoped(:conditions => ['priority >= ?', Worker.min_priority]) if Worker.min_priority
39
36
  scope = scope.scoped(:conditions => ['priority <= ?', Worker.max_priority]) if Worker.max_priority
40
- scope.by_priority
41
- end
42
37
 
43
- # Reserve a single job in a single update query. This causes workers to serialize on the
44
- # database and avoids contention.
45
- def self.reserve(worker, max_run_time = Worker.max_run_time)
46
- affected_rows = 0
47
38
  ::ActiveRecord::Base.silence do
48
- affected_rows = jobs_available_to_worker(worker.name, max_run_time).limit(1).update_all(["locked_at = ?, locked_by = ?", db_time_now, worker.name])
39
+ scope.by_priority.all(:limit => limit)
49
40
  end
41
+ end
50
42
 
43
+ # Lock this job for this worker.
44
+ # Returns true if we have the lock, false otherwise.
45
+ def lock_exclusively!(max_run_time, worker)
46
+ now = self.class.db_time_now
47
+ affected_rows = if locked_by != worker
48
+ # We don't own this job so we will update the locked_by name and the locked_at
49
+ self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?) and (run_at <= ?)", id, (now - max_run_time.to_i), now])
50
+ else
51
+ # We already own this job, this may happen if the job queue crashes.
52
+ # Simply resume and update the locked_at
53
+ self.class.update_all(["locked_at = ?", now], ["id = ? and locked_by = ?", id, worker])
54
+ end
51
55
  if affected_rows == 1
52
- locked_by_worker(worker.name, max_run_time).first
56
+ self.locked_at = now
57
+ self.locked_by = worker
58
+ self.locked_at_will_change!
59
+ self.locked_by_will_change!
60
+ return true
53
61
  else
54
- nil
62
+ return false
55
63
  end
56
64
  end
57
65
 
@@ -23,9 +23,13 @@ module Delayed
23
23
  unless options[:payload_object].respond_to?(:perform)
24
24
  raise ArgumentError, 'Cannot enqueue items which do not respond to perform'
25
25
  end
26
-
27
- self.create(options).tap do |job|
28
- job.hook(:enqueue)
26
+
27
+ if Delayed::Worker.delay_jobs
28
+ self.create(options).tap do |job|
29
+ job.hook(:enqueue)
30
+ end
31
+ else
32
+ options[:payload_object].perform
29
33
  end
30
34
  end
31
35
 
@@ -11,6 +11,7 @@ shared_examples_for 'a delayed_job backend' do
11
11
  Delayed::Worker.max_priority = nil
12
12
  Delayed::Worker.min_priority = nil
13
13
  Delayed::Worker.default_priority = 99
14
+ Delayed::Worker.delay_jobs = true
14
15
  SimpleJob.runs = 0
15
16
  described_class.delete_all
16
17
  end
@@ -57,6 +58,12 @@ shared_examples_for 'a delayed_job backend' do
57
58
  described_class.enqueue SimpleJob.new
58
59
  described_class.count.should == 1
59
60
  end
61
+
62
+ it "should not increase count after enqueuing items when delay_jobs is false" do
63
+ Delayed::Worker.delay_jobs = false
64
+ described_class.enqueue SimpleJob.new
65
+ described_class.count.should == 0
66
+ end
60
67
 
61
68
  it "should be able to set priority [DEPRECATED]" do
62
69
  silence_warnings do
@@ -155,6 +162,17 @@ shared_examples_for 'a delayed_job backend' do
155
162
  described_class.reserve(worker).should be_nil
156
163
  end
157
164
 
165
+ it "should reserve jobs scheduled for the past" do
166
+ job = create_job :run_at => described_class.db_time_now - 1.minute
167
+ described_class.reserve(worker).should == job
168
+ end
169
+
170
+ it "should reserve jobs scheduled for the past when time zones are involved" do
171
+ Time.zone = 'US/Eastern'
172
+ job = create_job :run_at => described_class.db_time_now - 1.minute.ago.in_time_zone
173
+ described_class.reserve(worker).should == job
174
+ end
175
+
158
176
  it "should not reserve jobs locked by other workers" do
159
177
  job = create_job
160
178
  other_worker = Delayed::Worker.new
@@ -10,7 +10,7 @@
10
10
  # If you want to use command line options, for example to start multiple workers,
11
11
  # define a Capistrano variable delayed_job_args:
12
12
  #
13
- # set :delayed_jobs_args, "-n 2"
13
+ # set :delayed_job_args, "-n 2"
14
14
  #
15
15
  # If you've got delayed_job workers running on a servers, you can also specify
16
16
  # which servers have delayed_job running and should be restarted after deploy.
@@ -6,11 +6,12 @@ require 'logger'
6
6
 
7
7
  module Delayed
8
8
  class Worker
9
- cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time, :default_priority, :sleep_delay, :logger
9
+ cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time, :default_priority, :sleep_delay, :logger, :delay_jobs
10
10
  self.sleep_delay = 5
11
11
  self.max_attempts = 25
12
12
  self.max_run_time = 4.hours
13
13
  self.default_priority = 0
14
+ self.delay_jobs = true
14
15
 
15
16
  # By default failed jobs are destroyed after too many attempts. If you want to keep them around
16
17
  # (perhaps to inspect the reason for the failure), set this to false.
@@ -13,7 +13,6 @@ class CreateDelayedJobs < ActiveRecord::Migration
13
13
  end
14
14
 
15
15
  add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
16
- add_index :delayed_jobs, :locked_by, :name => 'delayed_jobs_locked_by'
17
16
  end
18
17
 
19
18
  def self.down
@@ -85,5 +85,32 @@ describe Delayed::MessageSending do
85
85
  job.run_at.should == run_at
86
86
  job.priority.should == 20
87
87
  end
88
+
89
+ class FairyTail
90
+ attr_accessor :happy_ending
91
+ def tell
92
+ @happy_ending = true
93
+ end
94
+ end
95
+
96
+ it "should not delay the job when delay_jobs is false" do
97
+ Delayed::Worker.delay_jobs = false
98
+ fairy_tail = FairyTail.new
99
+ lambda {
100
+ lambda {
101
+ fairy_tail.delay.tell
102
+ }.should change(fairy_tail, :happy_ending).from(nil).to(true)
103
+ }.should_not change { Delayed::Job.count }
104
+ end
105
+
106
+ it "should delay the job when delay_jobs is true" do
107
+ Delayed::Worker.delay_jobs = true
108
+ fairy_tail = FairyTail.new
109
+ lambda {
110
+ lambda {
111
+ fairy_tail.delay.tell
112
+ }.should_not change(fairy_tail, :happy_ending)
113
+ }.should change { Delayed::Job.count }.by(1)
114
+ end
88
115
  end
89
116
  end
metadata CHANGED
@@ -1,130 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
4
  prerelease: false
6
5
  segments:
7
6
  - 2
8
7
  - 1
9
- - 2
10
- version: 2.1.2
8
+ - 3
9
+ version: 2.1.3
11
10
  platform: ruby
12
11
  authors:
12
+ - Chris Gaffney
13
13
  - Brandon Keepers
14
14
  - "Tobias L\xC3\xBCtke"
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-12-01 00:00:00 -05:00
19
+ date: 2011-01-20 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: daemons
24
- prerelease: false
25
24
  requirement: &id001 !ruby/object:Gem::Requirement
26
25
  none: false
27
26
  requirements:
28
27
  - - ">="
29
28
  - !ruby/object:Gem::Version
30
- hash: 3
31
29
  segments:
32
30
  - 0
33
31
  version: "0"
34
32
  type: :runtime
33
+ prerelease: false
35
34
  version_requirements: *id001
36
35
  - !ruby/object:Gem::Dependency
37
36
  name: activesupport
38
- prerelease: false
39
37
  requirement: &id002 !ruby/object:Gem::Requirement
40
38
  none: false
41
39
  requirements:
42
40
  - - ~>
43
41
  - !ruby/object:Gem::Version
44
- hash: 7
45
42
  segments:
46
43
  - 3
47
44
  - 0
48
45
  version: "3.0"
49
46
  type: :runtime
47
+ prerelease: false
50
48
  version_requirements: *id002
51
49
  - !ruby/object:Gem::Dependency
52
50
  name: rspec
53
- prerelease: false
54
51
  requirement: &id003 !ruby/object:Gem::Requirement
55
52
  none: false
56
53
  requirements:
57
54
  - - ~>
58
55
  - !ruby/object:Gem::Version
59
- hash: 3
60
56
  segments:
61
57
  - 2
62
58
  - 0
63
59
  version: "2.0"
64
60
  type: :development
61
+ prerelease: false
65
62
  version_requirements: *id003
66
63
  - !ruby/object:Gem::Dependency
67
64
  name: rake
68
- prerelease: false
69
65
  requirement: &id004 !ruby/object:Gem::Requirement
70
66
  none: false
71
67
  requirements:
72
68
  - - ">="
73
69
  - !ruby/object:Gem::Version
74
- hash: 3
75
70
  segments:
76
71
  - 0
77
72
  version: "0"
78
73
  type: :development
74
+ prerelease: false
79
75
  version_requirements: *id004
80
76
  - !ruby/object:Gem::Dependency
81
77
  name: rails
82
- prerelease: false
83
78
  requirement: &id005 !ruby/object:Gem::Requirement
84
79
  none: false
85
80
  requirements:
86
81
  - - ~>
87
82
  - !ruby/object:Gem::Version
88
- hash: 7
89
83
  segments:
90
84
  - 3
91
85
  - 0
92
86
  version: "3.0"
93
87
  type: :development
88
+ prerelease: false
94
89
  version_requirements: *id005
95
90
  - !ruby/object:Gem::Dependency
96
- name: sqlite3-ruby
97
- prerelease: false
91
+ name: sqlite3
98
92
  requirement: &id006 !ruby/object:Gem::Requirement
99
93
  none: false
100
94
  requirements:
101
95
  - - ">="
102
96
  - !ruby/object:Gem::Version
103
- hash: 3
104
97
  segments:
105
98
  - 0
106
99
  version: "0"
107
100
  type: :development
101
+ prerelease: false
108
102
  version_requirements: *id006
109
103
  - !ruby/object:Gem::Dependency
110
104
  name: mysql
111
- prerelease: false
112
105
  requirement: &id007 !ruby/object:Gem::Requirement
113
106
  none: false
114
107
  requirements:
115
108
  - - ">="
116
109
  - !ruby/object:Gem::Version
117
- hash: 3
118
110
  segments:
119
111
  - 0
120
112
  version: "0"
121
113
  type: :development
114
+ prerelease: false
122
115
  version_requirements: *id007
123
116
  description: |-
124
117
  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.
125
118
 
126
119
  This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job).
127
- email: brandon@collectiveidea.com
120
+ email:
121
+ - chris@collectiveidea.com
122
+ - brandon@opensoul.org
128
123
  executables: []
129
124
 
130
125
  extensions: []
@@ -183,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
183
178
  requirements:
184
179
  - - ">="
185
180
  - !ruby/object:Gem::Version
186
- hash: 3
181
+ hash: -1896469102761102405
187
182
  segments:
188
183
  - 0
189
184
  version: "0"
@@ -192,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
192
187
  requirements:
193
188
  - - ">="
194
189
  - !ruby/object:Gem::Version
195
- hash: 3
190
+ hash: -1896469102761102405
196
191
  segments:
197
192
  - 0
198
193
  version: "0"