delayed_job 2.0.8 → 2.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.textile +14 -58
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/benchmarks.rb +33 -0
- data/delayed_job.gemspec +125 -0
- data/init.rb +1 -0
- data/lib/delayed/backend/active_record.rb +11 -13
- data/lib/delayed/backend/base.rb +14 -58
- data/lib/delayed/backend/couch_rest.rb +109 -0
- data/lib/delayed/backend/data_mapper.rb +8 -12
- data/lib/delayed/backend/mongo_mapper.rb +8 -12
- data/lib/delayed/command.rb +3 -8
- data/lib/delayed/message_sending.rb +10 -19
- data/lib/delayed/performable_method.rb +5 -48
- data/lib/delayed/railtie.rb +4 -0
- data/lib/delayed/recipes.rb +5 -24
- data/lib/delayed/worker.rb +26 -27
- data/lib/delayed/yaml_ext.rb +40 -0
- data/lib/delayed_job.rb +1 -1
- data/lib/generators/delayed_job/delayed_job_generator.rb +34 -0
- data/lib/generators/delayed_job/templates/migration.rb +21 -0
- data/lib/generators/delayed_job/templates/script +5 -0
- data/spec/autoloaded/clazz.rb +7 -0
- data/spec/autoloaded/struct.rb +7 -0
- data/spec/backend/couch_rest_job_spec.rb +15 -0
- data/spec/backend/mongo_mapper_job_spec.rb +11 -11
- data/spec/backend/shared_backend_spec.rb +41 -109
- data/spec/message_sending_spec.rb +1 -46
- data/spec/performable_method_spec.rb +22 -45
- data/spec/sample_jobs.rb +0 -1
- data/spec/setup/couch_rest.rb +7 -0
- data/spec/spec_helper.rb +6 -3
- data/spec/worker_spec.rb +6 -29
- metadata +174 -260
- data/lib/delayed/deserialization_error.rb +0 -4
- data/spec/delayed_method_spec.rb +0 -46
- data/spec/story_spec.rb +0 -17
data/.gitignore
ADDED
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
|
+
Delated_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
|
|
@@ -9,24 +9,21 @@ It is a direct extraction from Shopify where the job table is responsible for a
|
|
9
9
|
* http downloads
|
10
10
|
* updating smart collections
|
11
11
|
* updating solr, our search server, after product changes
|
12
|
-
* batch imports
|
13
|
-
* spam checks
|
12
|
+
* batch imports
|
13
|
+
* spam checks
|
14
14
|
|
15
15
|
h2. Installation
|
16
16
|
|
17
|
-
This version is for Rails 2.x only. For rails 3 support, install delayed_job 2.1.
|
18
|
-
|
19
17
|
To install as a gem, add the following to @config/environment.rb@:
|
20
18
|
|
21
19
|
<pre>
|
22
|
-
config.gem 'delayed_job'
|
20
|
+
config.gem 'delayed_job'
|
23
21
|
</pre>
|
24
22
|
|
25
23
|
Rake tasks are not automatically loaded from gems, so you'll need to add the following to your Rakefile:
|
26
24
|
|
27
25
|
<pre>
|
28
26
|
begin
|
29
|
-
gem 'delayed_job', '~>2.0.4'
|
30
27
|
require 'delayed/tasks'
|
31
28
|
rescue LoadError
|
32
29
|
STDERR.puts "Run `rake gems:install` to install delayed_job"
|
@@ -36,15 +33,11 @@ end
|
|
36
33
|
To install as a plugin:
|
37
34
|
|
38
35
|
<pre>
|
39
|
-
script/plugin install git://github.com/collectiveidea/delayed_job.git
|
36
|
+
script/plugin install git://github.com/collectiveidea/delayed_job.git
|
40
37
|
</pre>
|
41
38
|
|
42
39
|
After delayed_job is installed, you will need to setup the backend.
|
43
40
|
|
44
|
-
h3. Dependencies
|
45
|
-
|
46
|
-
delayed_job depends upon version 1.0.10 of the daemons gem. delayed_job is incompatible with the newest (1.1.0) daemons gem.
|
47
|
-
|
48
41
|
h2. Backends
|
49
42
|
|
50
43
|
delayed_job supports multiple backends for storing the job queue. There are currently implementations for Active Record, MongoMapper, and DataMapper.
|
@@ -60,12 +53,8 @@ $ rake db:migrate
|
|
60
53
|
|
61
54
|
h3. MongoMapper
|
62
55
|
|
63
|
-
You must use @MongoMapper.setup@ in the initializer:
|
64
|
-
|
65
56
|
<pre>
|
66
|
-
|
67
|
-
MongoMapper.setup(config, Rails.env)
|
68
|
-
|
57
|
+
# config/initializers/delayed_job.rb
|
69
58
|
Delayed::Worker.backend = :mongo_mapper
|
70
59
|
</pre>
|
71
60
|
|
@@ -103,39 +92,6 @@ device = Device.new
|
|
103
92
|
device.deliver
|
104
93
|
</pre>
|
105
94
|
|
106
|
-
handle_asynchronously can take as options anything you can pass to delay. In addition the values can be Proc objects allowing call time evaluation of the value. For some examples:
|
107
|
-
|
108
|
-
<pre>
|
109
|
-
class LongTasks
|
110
|
-
def send_mailer
|
111
|
-
# Some other code
|
112
|
-
end
|
113
|
-
handle_asynchronously :send_mailer, :priority => 20
|
114
|
-
|
115
|
-
def in_the_future
|
116
|
-
# Some other code
|
117
|
-
end
|
118
|
-
# 5.minutes.from_now will be evaluated when in_the_future is called
|
119
|
-
handle_asynchronously :in_the_future, :run_at => Proc.new { 5.minutes.from_now }
|
120
|
-
|
121
|
-
def self.when_to_run
|
122
|
-
2.hours.from_now
|
123
|
-
end
|
124
|
-
|
125
|
-
def call_a_class_method
|
126
|
-
# Some other code
|
127
|
-
end
|
128
|
-
handle_asynchronously :call_a_class_method, :run_at => Proc.new { when_to_run }
|
129
|
-
|
130
|
-
attr_reader :how_important
|
131
|
-
|
132
|
-
def call_an_instance_method
|
133
|
-
# Some other code
|
134
|
-
end
|
135
|
-
handle_asynchronously :call_an_instance_method, :priority => Proc.new {|i| i.how_important }
|
136
|
-
end
|
137
|
-
</pre>
|
138
|
-
|
139
95
|
h2. Running Jobs
|
140
96
|
|
141
97
|
@script/delayed_job@ can be used to manage a background process which will start working off jobs. Make sure you've run `script/generate delayed_job`.
|
@@ -151,19 +107,19 @@ $ RAILS_ENV=production script/delayed_job stop
|
|
151
107
|
|
152
108
|
Workers can be running on any computer, as long as they have access to the database and their clock is in sync. Keep in mind that each worker will check the database at least every 5 seconds.
|
153
109
|
|
154
|
-
You can also invoke @rake jobs:work@ which will start working off jobs. You can cancel the rake task with @CTRL-C@.
|
110
|
+
You can also invoke @rake jobs:work@ which will start working off jobs. You can cancel the rake task with @CTRL-C@.
|
155
111
|
|
156
112
|
h2. Custom Jobs
|
157
113
|
|
158
|
-
Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table. Job objects are serialized to yaml so that they can later be resurrected by the job runner.
|
114
|
+
Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table. Job objects are serialized to yaml so that they can later be resurrected by the job runner.
|
159
115
|
|
160
116
|
<pre>
|
161
117
|
class NewsletterJob < Struct.new(:text, :emails)
|
162
118
|
def perform
|
163
119
|
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
167
123
|
Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
|
168
124
|
</pre>
|
169
125
|
|
@@ -173,17 +129,17 @@ You can also add an optional on_permanent_failure method which will run if the j
|
|
173
129
|
class ParanoidNewsletterJob < NewsletterJob
|
174
130
|
def perform
|
175
131
|
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
176
|
-
end
|
132
|
+
end
|
177
133
|
|
178
134
|
def on_permanent_failure
|
179
135
|
page_sysadmin_in_the_middle_of_the_night
|
180
136
|
end
|
181
|
-
end
|
137
|
+
end
|
182
138
|
</pre>
|
183
139
|
|
184
140
|
h2. Gory Details
|
185
141
|
|
186
|
-
The library evolves around a delayed_jobs table which looks as follows:
|
142
|
+
The library evolves around a delayed_jobs table which looks as follows:
|
187
143
|
|
188
144
|
<pre>
|
189
145
|
create_table :delayed_jobs, :force => true do |table|
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
begin
|
3
|
+
require 'jeweler'
|
4
|
+
rescue LoadError
|
5
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
Jeweler::Tasks.new do |s|
|
10
|
+
s.name = "delayed_job"
|
11
|
+
s.summary = "Database-backed asynchronous priority queue system -- Extracted from Shopify"
|
12
|
+
s.email = "tobi@leetsoft.com"
|
13
|
+
s.homepage = "http://github.com/collectiveidea/delayed_job"
|
14
|
+
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.\n\nThis gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job)."
|
15
|
+
s.authors = ["Brandon Keepers", "Tobias Lütke"]
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
|
19
|
+
s.extra_rdoc_files = ["README.textile"]
|
20
|
+
|
21
|
+
s.test_files = Dir['spec/*_spec.rb']
|
22
|
+
|
23
|
+
s.add_dependency "daemons"
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
s.add_development_dependency "sqlite3-ruby"
|
26
|
+
s.add_development_dependency "activerecord"
|
27
|
+
s.add_development_dependency "mongo_mapper"
|
28
|
+
s.add_development_dependency "dm-core"
|
29
|
+
s.add_development_dependency "dm-observer"
|
30
|
+
s.add_development_dependency "dm-aggregates"
|
31
|
+
s.add_development_dependency "dm-validations"
|
32
|
+
s.add_development_dependency "do_sqlite3"
|
33
|
+
s.add_development_dependency "couchrest"
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'spec/rake/spectask'
|
37
|
+
|
38
|
+
|
39
|
+
task :default do
|
40
|
+
%w(2.3.5 3.0.0.beta3).each do |version|
|
41
|
+
puts "Running specs with Rails #{version}"
|
42
|
+
system("RAILS_VERSION=#{version} rake -s spec;")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'Run the specs'
|
47
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
48
|
+
t.libs << 'lib'
|
49
|
+
t.pattern = 'spec/*_spec.rb'
|
50
|
+
t.verbose = true
|
51
|
+
end
|
52
|
+
task :spec => :check_dependencies
|
53
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.0.pre
|
data/benchmarks.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/lib')
|
2
|
+
require 'rubygems'
|
3
|
+
require 'logger'
|
4
|
+
require 'delayed_job'
|
5
|
+
require 'benchmark'
|
6
|
+
|
7
|
+
RAILS_ENV = 'test'
|
8
|
+
|
9
|
+
Delayed::Worker.logger = Logger.new('/dev/null')
|
10
|
+
|
11
|
+
BACKENDS = []
|
12
|
+
Dir.glob("#{File.dirname(__FILE__)}/spec/setup/*.rb") do |backend|
|
13
|
+
begin
|
14
|
+
backend = File.basename(backend, '.rb')
|
15
|
+
require "spec/setup/#{backend}"
|
16
|
+
BACKENDS << backend.to_sym
|
17
|
+
rescue LoadError
|
18
|
+
puts "Unable to load #{backend} backend! #{$!}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
Benchmark.bm(10) do |x|
|
24
|
+
BACKENDS.each do |backend|
|
25
|
+
require "spec/setup/#{backend}"
|
26
|
+
Delayed::Worker.backend = backend
|
27
|
+
|
28
|
+
n = 10000
|
29
|
+
n.times { "foo".delay.length }
|
30
|
+
|
31
|
+
x.report(backend.to_s) { Delayed::Worker.new(:quiet => true).work_off(n) }
|
32
|
+
end
|
33
|
+
end
|
data/delayed_job.gemspec
ADDED
@@ -0,0 +1,125 @@
|
|
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{delayed_job}
|
8
|
+
s.version = "2.1.0.pre"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Brandon Keepers", "Tobias L\303\274tke"]
|
12
|
+
s.date = %q{2010-05-21}
|
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
|
+
|
15
|
+
This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job).}
|
16
|
+
s.email = %q{tobi@leetsoft.com}
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README.textile"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".gitignore",
|
22
|
+
"MIT-LICENSE",
|
23
|
+
"README.textile",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"benchmarks.rb",
|
27
|
+
"contrib/delayed_job.monitrc",
|
28
|
+
"contrib/delayed_job_multiple.monitrc",
|
29
|
+
"delayed_job.gemspec",
|
30
|
+
"generators/delayed_job/delayed_job_generator.rb",
|
31
|
+
"generators/delayed_job/templates/migration.rb",
|
32
|
+
"generators/delayed_job/templates/script",
|
33
|
+
"init.rb",
|
34
|
+
"lib/delayed/backend/active_record.rb",
|
35
|
+
"lib/delayed/backend/base.rb",
|
36
|
+
"lib/delayed/backend/couch_rest.rb",
|
37
|
+
"lib/delayed/backend/data_mapper.rb",
|
38
|
+
"lib/delayed/backend/mongo_mapper.rb",
|
39
|
+
"lib/delayed/command.rb",
|
40
|
+
"lib/delayed/message_sending.rb",
|
41
|
+
"lib/delayed/performable_method.rb",
|
42
|
+
"lib/delayed/railtie.rb",
|
43
|
+
"lib/delayed/recipes.rb",
|
44
|
+
"lib/delayed/tasks.rb",
|
45
|
+
"lib/delayed/worker.rb",
|
46
|
+
"lib/delayed/yaml_ext.rb",
|
47
|
+
"lib/delayed_job.rb",
|
48
|
+
"lib/generators/delayed_job/delayed_job_generator.rb",
|
49
|
+
"lib/generators/delayed_job/templates/migration.rb",
|
50
|
+
"lib/generators/delayed_job/templates/script",
|
51
|
+
"rails/init.rb",
|
52
|
+
"recipes/delayed_job.rb",
|
53
|
+
"spec/autoloaded/clazz.rb",
|
54
|
+
"spec/autoloaded/struct.rb",
|
55
|
+
"spec/backend/active_record_job_spec.rb",
|
56
|
+
"spec/backend/couch_rest_job_spec.rb",
|
57
|
+
"spec/backend/data_mapper_job_spec.rb",
|
58
|
+
"spec/backend/mongo_mapper_job_spec.rb",
|
59
|
+
"spec/backend/shared_backend_spec.rb",
|
60
|
+
"spec/message_sending_spec.rb",
|
61
|
+
"spec/performable_method_spec.rb",
|
62
|
+
"spec/sample_jobs.rb",
|
63
|
+
"spec/setup/active_record.rb",
|
64
|
+
"spec/setup/couch_rest.rb",
|
65
|
+
"spec/setup/data_mapper.rb",
|
66
|
+
"spec/setup/mongo_mapper.rb",
|
67
|
+
"spec/spec_helper.rb",
|
68
|
+
"spec/worker_spec.rb",
|
69
|
+
"tasks/jobs.rake"
|
70
|
+
]
|
71
|
+
s.homepage = %q{http://github.com/collectiveidea/delayed_job}
|
72
|
+
s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
|
73
|
+
s.require_paths = ["lib"]
|
74
|
+
s.rubygems_version = %q{1.3.6}
|
75
|
+
s.summary = %q{Database-backed asynchronous priority queue system -- Extracted from Shopify}
|
76
|
+
s.test_files = [
|
77
|
+
"spec/message_sending_spec.rb",
|
78
|
+
"spec/performable_method_spec.rb",
|
79
|
+
"spec/worker_spec.rb"
|
80
|
+
]
|
81
|
+
|
82
|
+
if s.respond_to? :specification_version then
|
83
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
84
|
+
s.specification_version = 3
|
85
|
+
|
86
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
87
|
+
s.add_runtime_dependency(%q<daemons>, [">= 0"])
|
88
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
89
|
+
s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
|
90
|
+
s.add_development_dependency(%q<activerecord>, [">= 0"])
|
91
|
+
s.add_development_dependency(%q<mongo_mapper>, [">= 0"])
|
92
|
+
s.add_development_dependency(%q<dm-core>, [">= 0"])
|
93
|
+
s.add_development_dependency(%q<dm-observer>, [">= 0"])
|
94
|
+
s.add_development_dependency(%q<dm-aggregates>, [">= 0"])
|
95
|
+
s.add_development_dependency(%q<dm-validations>, [">= 0"])
|
96
|
+
s.add_development_dependency(%q<do_sqlite3>, [">= 0"])
|
97
|
+
s.add_development_dependency(%q<couchrest>, [">= 0"])
|
98
|
+
else
|
99
|
+
s.add_dependency(%q<daemons>, [">= 0"])
|
100
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
101
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
102
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
103
|
+
s.add_dependency(%q<mongo_mapper>, [">= 0"])
|
104
|
+
s.add_dependency(%q<dm-core>, [">= 0"])
|
105
|
+
s.add_dependency(%q<dm-observer>, [">= 0"])
|
106
|
+
s.add_dependency(%q<dm-aggregates>, [">= 0"])
|
107
|
+
s.add_dependency(%q<dm-validations>, [">= 0"])
|
108
|
+
s.add_dependency(%q<do_sqlite3>, [">= 0"])
|
109
|
+
s.add_dependency(%q<couchrest>, [">= 0"])
|
110
|
+
end
|
111
|
+
else
|
112
|
+
s.add_dependency(%q<daemons>, [">= 0"])
|
113
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
114
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
115
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
116
|
+
s.add_dependency(%q<mongo_mapper>, [">= 0"])
|
117
|
+
s.add_dependency(%q<dm-core>, [">= 0"])
|
118
|
+
s.add_dependency(%q<dm-observer>, [">= 0"])
|
119
|
+
s.add_dependency(%q<dm-aggregates>, [">= 0"])
|
120
|
+
s.add_dependency(%q<dm-validations>, [">= 0"])
|
121
|
+
s.add_dependency(%q<do_sqlite3>, [">= 0"])
|
122
|
+
s.add_dependency(%q<couchrest>, [">= 0"])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'rails', 'init')
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
|
3
3
|
class ActiveRecord::Base
|
4
|
-
|
5
|
-
if id
|
6
|
-
find(id)
|
7
|
-
else
|
8
|
-
super
|
9
|
-
end
|
10
|
-
end
|
4
|
+
yaml_as "tag:ruby.yaml.org,2002:ActiveRecord"
|
11
5
|
|
12
|
-
def
|
13
|
-
|
6
|
+
def self.yaml_new(klass, tag, val)
|
7
|
+
klass.find(val['attributes']['id'])
|
8
|
+
rescue ActiveRecord::RecordNotFound
|
9
|
+
nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_yaml_properties
|
13
|
+
['@attributes']
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -63,10 +63,8 @@ module Delayed
|
|
63
63
|
self.class.update_all(["locked_at = ?", now], ["id = ? and locked_by = ?", id, worker])
|
64
64
|
end
|
65
65
|
if affected_rows == 1
|
66
|
-
self.locked_at
|
67
|
-
self.locked_by
|
68
|
-
self.locked_at_will_change!
|
69
|
-
self.locked_by_will_change!
|
66
|
+
self.locked_at = now
|
67
|
+
self.locked_by = worker
|
70
68
|
return true
|
71
69
|
else
|
72
70
|
return false
|
data/lib/delayed/backend/base.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Delayed
|
2
2
|
module Backend
|
3
|
+
class DeserializationError < StandardError
|
4
|
+
end
|
5
|
+
|
3
6
|
module Base
|
4
7
|
def self.included(base)
|
5
8
|
base.extend ClassMethods
|
@@ -13,19 +16,11 @@ module Delayed
|
|
13
16
|
raise ArgumentError, 'Cannot enqueue items which do not respond to perform'
|
14
17
|
end
|
15
18
|
|
16
|
-
priority = args.first ||
|
19
|
+
priority = args.first || 0
|
17
20
|
run_at = args[1]
|
18
21
|
self.create(:payload_object => object, :priority => priority.to_i, :run_at => run_at)
|
19
22
|
end
|
20
|
-
|
21
|
-
def reserve(worker, max_run_time = Worker.max_run_time)
|
22
|
-
# We get up to 5 jobs from the db. In case we cannot get exclusive access to a job we try the next.
|
23
|
-
# this leads to a more even distribution of jobs across the worker processes
|
24
|
-
find_available(worker.name, 5, max_run_time).detect do |job|
|
25
|
-
job.lock_exclusively!(max_run_time, worker.name)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
23
|
+
|
29
24
|
# Hook method that is called before a new worker is forked
|
30
25
|
def before_fork
|
31
26
|
end
|
@@ -50,20 +45,19 @@ module Delayed
|
|
50
45
|
def name
|
51
46
|
@name ||= begin
|
52
47
|
payload = payload_object
|
53
|
-
|
54
|
-
payload.display_name
|
55
|
-
else
|
56
|
-
payload.class.name
|
57
|
-
end
|
48
|
+
payload.respond_to?(:display_name) ? payload.display_name : payload.class.name
|
58
49
|
end
|
59
50
|
end
|
60
51
|
|
61
52
|
def payload_object=(object)
|
62
|
-
self
|
53
|
+
self.handler = object.to_yaml
|
63
54
|
end
|
64
55
|
|
65
56
|
def payload_object
|
66
|
-
@payload_object ||=
|
57
|
+
@payload_object ||= YAML.load(self.handler)
|
58
|
+
rescue TypeError, LoadError, NameError => e
|
59
|
+
raise DeserializationError,
|
60
|
+
"Job failed to load: #{e.message}. Try to manually require the required file. Handler: #{handler.inspect}"
|
67
61
|
end
|
68
62
|
|
69
63
|
# Moved into its own method so that new_relic can trace it.
|
@@ -76,51 +70,13 @@ module Delayed
|
|
76
70
|
self.locked_at = nil
|
77
71
|
self.locked_by = nil
|
78
72
|
end
|
79
|
-
|
80
|
-
def reschedule_at
|
81
|
-
payload_object.respond_to?(:reschedule_at) ?
|
82
|
-
payload_object.reschedule_at(self.class.db_time_now, attempts) :
|
83
|
-
self.class.db_time_now + (attempts ** 4) + 5
|
84
|
-
end
|
85
|
-
|
86
|
-
def max_attempts
|
87
|
-
payload_object.max_attempts if payload_object.respond_to?(:max_attempts)
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
def deserialize(source)
|
93
|
-
handler = YAML.load(source) rescue nil
|
94
|
-
|
95
|
-
unless handler.respond_to?(:perform)
|
96
|
-
if handler.nil? && source =~ ParseObjectFromYaml
|
97
|
-
handler_class = $1
|
98
|
-
end
|
99
|
-
attempt_to_load(handler_class || handler.class)
|
100
|
-
handler = YAML.load(source)
|
101
|
-
end
|
102
|
-
|
103
|
-
return handler if handler.respond_to?(:perform)
|
104
|
-
|
105
|
-
raise DeserializationError,
|
106
|
-
'Job failed to load: Unknown handler. Try to manually require the appropriate file.'
|
107
|
-
rescue TypeError, LoadError, NameError, ArgumentError => e
|
108
|
-
raise DeserializationError,
|
109
|
-
"Job failed to load: #{e.message}. Try to manually require the required file."
|
110
|
-
end
|
111
|
-
|
112
|
-
# Constantize the object so that ActiveSupport can attempt
|
113
|
-
# its auto loading magic. Will raise LoadError if not successful.
|
114
|
-
def attempt_to_load(klass)
|
115
|
-
klass.constantize
|
116
|
-
end
|
117
73
|
|
118
74
|
protected
|
119
75
|
|
120
76
|
def set_default_run_at
|
121
77
|
self.run_at ||= self.class.db_time_now
|
122
|
-
end
|
123
|
-
|
78
|
+
end
|
79
|
+
|
124
80
|
end
|
125
81
|
end
|
126
|
-
end
|
82
|
+
end
|