collectiveidea-delayed_job 1.8.0 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +122 -49
- data/VERSION +1 -1
- data/delayed_job.gemspec +4 -4
- data/generators/delayed_job/delayed_job_generator.rb +13 -2
- data/generators/delayed_job/templates/script +2 -4
- data/lib/delayed/command.rb +7 -8
- data/lib/delayed/message_sending.rb +4 -3
- data/{tasks → lib/delayed}/tasks.rb +0 -0
- data/lib/delayed_job.rb +1 -1
- data/tasks/jobs.rake +1 -1
- metadata +5 -4
data/README.textile
CHANGED
@@ -11,16 +11,113 @@ It is a direct extraction from Shopify where the job table is responsible for a
|
|
11
11
|
* updating solr, our search server, after product changes
|
12
12
|
* batch imports
|
13
13
|
* spam checks
|
14
|
-
|
15
|
-
h2.
|
16
|
-
|
14
|
+
|
15
|
+
h2. Installation
|
16
|
+
|
17
|
+
To install as a gem, add the following to @config/environment.rb@:
|
18
|
+
|
19
|
+
<pre>
|
20
|
+
config.gem 'collectiveidea-delayed_job', :lib => 'delayed_job',
|
21
|
+
:source => 'http://gems.github.com'
|
22
|
+
</pre>
|
23
|
+
|
24
|
+
Rake tasks are not automatically loaded from gems, so you'll need to add the following to your Rakefile:
|
25
|
+
|
26
|
+
<pre>
|
27
|
+
begin
|
28
|
+
require 'delayed/tasks'
|
29
|
+
rescue LoadError
|
30
|
+
STDERR.puts "Run `rake gems:install` to install delayed_job"
|
31
|
+
end
|
32
|
+
</pre>
|
33
|
+
|
34
|
+
To install as a plugin:
|
35
|
+
|
36
|
+
<pre>
|
37
|
+
script/plugin install git://github.com/collectiveidea/delayed_job.git
|
38
|
+
</pre>
|
39
|
+
|
40
|
+
After delayed_job is installed, run:
|
41
|
+
|
42
|
+
<pre>
|
43
|
+
script/generate delayed_job
|
44
|
+
rake db:migrate
|
45
|
+
</pre>
|
46
|
+
|
47
|
+
h2. Upgrading to 1.8
|
48
|
+
|
49
|
+
If you are upgrading from a previous release, you will need to generate the new @script/delayed_job@:
|
50
|
+
|
51
|
+
<pre>
|
52
|
+
script/generate delayed_job --skip-migration
|
53
|
+
</pre>
|
54
|
+
|
55
|
+
h2. Queuing Jobs
|
56
|
+
|
57
|
+
Call @#send_later(method, params)@ on any object and it will be processed in the background.
|
58
|
+
|
59
|
+
<pre>
|
60
|
+
# without delayed_job
|
61
|
+
Notifier.deliver_signup(@user)
|
62
|
+
|
63
|
+
# with delayed_job
|
64
|
+
Notifier.send_later :deliver_signup, @user
|
65
|
+
</pre>
|
66
|
+
|
67
|
+
If a method should always be run in the background, you can call @#handle_asynchronously@ after the method declaration:
|
68
|
+
|
69
|
+
<pre>
|
70
|
+
class Device
|
71
|
+
def deliver
|
72
|
+
# long running method
|
73
|
+
end
|
74
|
+
handle_asynchronously :deliver
|
75
|
+
end
|
76
|
+
|
77
|
+
device = Device.new
|
78
|
+
device.deliver
|
79
|
+
</pre>
|
80
|
+
|
81
|
+
h2. Running Jobs
|
82
|
+
|
83
|
+
@script/delayed_job@ can be used to manage a background process which will start working off jobs.
|
84
|
+
|
85
|
+
<pre>
|
86
|
+
$ ruby script/delayed_job -e production start
|
87
|
+
$ ruby script/delayed_job -e production stop
|
88
|
+
|
89
|
+
# Runs two workers in separate processes.
|
90
|
+
$ ruby script/delayed_job -e production -n 2 start
|
91
|
+
$ ruby script/delayed_job -e production stop
|
92
|
+
</pre>
|
93
|
+
|
94
|
+
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.
|
95
|
+
|
96
|
+
You can also invoke @rake jobs:work@ which will start working off jobs. You can cancel the rake task with @CTRL-C@.
|
97
|
+
|
98
|
+
h2. Custom Jobs
|
99
|
+
|
100
|
+
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.
|
101
|
+
|
102
|
+
<pre>
|
103
|
+
class NewsletterJob < Struct.new(:text, :emails)
|
104
|
+
def perform
|
105
|
+
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
|
110
|
+
</pre>
|
111
|
+
|
112
|
+
h2. Gory Details
|
113
|
+
|
17
114
|
The library evolves around a delayed_jobs table which looks as follows:
|
18
115
|
|
19
116
|
create_table :delayed_jobs, :force => true do |table|
|
20
117
|
table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
|
21
118
|
table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
|
22
119
|
table.text :handler # YAML-encoded string of the object that will do work
|
23
|
-
table.
|
120
|
+
table.text :last_error # reason for last failure (See Note below)
|
24
121
|
table.datetime :run_at # When to run. Could be Time.now for immediately, or sometime in the future.
|
25
122
|
table.datetime :locked_at # Set when a client is working on this object
|
26
123
|
table.datetime :failed_at # Set when all retries have failed (actually, by default, the record is deleted instead)
|
@@ -41,58 +138,34 @@ Delayed::Job.destroy_failed_jobs = false. The failed jobs will be marked with no
|
|
41
138
|
|
42
139
|
Here is an example of changing job parameters in Rails:
|
43
140
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
h2. Usage
|
141
|
+
<pre>
|
142
|
+
# config/initializers/delayed_job_config.rb
|
143
|
+
Delayed::Job.destroy_failed_jobs = false
|
144
|
+
silence_warnings do
|
145
|
+
Delayed::Job.const_set("MAX_ATTEMPTS", 3)
|
146
|
+
Delayed::Job.const_set("MAX_RUN_TIME", 5.minutes)
|
147
|
+
end
|
148
|
+
</pre>
|
55
149
|
|
56
|
-
|
57
|
-
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)
|
60
|
-
def perform
|
61
|
-
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
|
66
|
-
|
67
|
-
There is also a second way to get jobs in the queue: send_later.
|
68
|
-
|
69
|
-
|
70
|
-
BatchImporter.new(Shop.find(1)).send_later(:import_massive_csv, massive_csv)
|
71
|
-
|
72
|
-
|
73
|
-
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
|
-
which are stored as their text representation and loaded from the database fresh when the job is actually run later.
|
75
|
-
|
76
|
-
|
77
|
-
h2. Running the jobs
|
150
|
+
h3. Cleaning up
|
78
151
|
|
79
|
-
|
152
|
+
You can invoke @rake jobs:clear@ to delete all jobs in the queue.
|
80
153
|
|
81
|
-
|
82
|
-
$ ruby script/delayed_job -e production -n 2 start
|
83
|
-
$ ruby script/delayed_job -e production stop
|
154
|
+
h2. How to contribute
|
84
155
|
|
85
|
-
|
156
|
+
If you find what looks like a bug:
|
86
157
|
|
87
|
-
|
88
|
-
|
89
|
-
|
158
|
+
# Check the GitHub issue tracker to see if anyone else has had the same issue.
|
159
|
+
http://github.com/collectiveidea/delayed_job/issues/
|
160
|
+
# If you don't see anything, create an issue with information on how to reproduce it.
|
90
161
|
|
91
|
-
|
162
|
+
If you want to contribute an enhancement or a fix:
|
92
163
|
|
93
|
-
|
94
|
-
|
95
|
-
|
164
|
+
# Fork the project on github.
|
165
|
+
http://github.com/collectiveidea/delayed_job/
|
166
|
+
# Make your changes with tests.
|
167
|
+
# Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
|
168
|
+
# Send a pull request.
|
96
169
|
|
97
170
|
h3. Changes
|
98
171
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.8.
|
1
|
+
1.8.1
|
data/delayed_job.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{delayed_job}
|
5
|
-
s.version = "1.8.
|
5
|
+
s.version = "1.8.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Tobias L\303\274tke"]
|
9
|
-
s.date = %q{2009-
|
9
|
+
s.date = %q{2009-09-06}
|
10
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
11
|
s.email = %q{tobi@leetsoft.com}
|
12
12
|
s.extra_rdoc_files = [
|
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
|
|
27
27
|
"lib/delayed/job.rb",
|
28
28
|
"lib/delayed/message_sending.rb",
|
29
29
|
"lib/delayed/performable_method.rb",
|
30
|
+
"lib/delayed/tasks.rb",
|
30
31
|
"lib/delayed/worker.rb",
|
31
32
|
"lib/delayed_job.rb",
|
32
33
|
"recipes/delayed_job.rb",
|
@@ -34,8 +35,7 @@ Gem::Specification.new do |s|
|
|
34
35
|
"spec/delayed_method_spec.rb",
|
35
36
|
"spec/job_spec.rb",
|
36
37
|
"spec/story_spec.rb",
|
37
|
-
"tasks/jobs.rake"
|
38
|
-
"tasks/tasks.rb"
|
38
|
+
"tasks/jobs.rake"
|
39
39
|
]
|
40
40
|
s.homepage = %q{http://github.com/tobi/delayed_job/tree/master}
|
41
41
|
s.rdoc_options = ["--main", "README.textile", "--inline-source", "--line-numbers"]
|
@@ -1,11 +1,22 @@
|
|
1
1
|
class DelayedJobGenerator < Rails::Generator::Base
|
2
|
+
default_options :skip_migration => false
|
2
3
|
|
3
4
|
def manifest
|
4
5
|
record do |m|
|
5
6
|
m.template 'script', 'script/delayed_job', :chmod => 0755
|
6
|
-
|
7
|
-
|
7
|
+
unless options[:skip_migration]
|
8
|
+
m.migration_template "migration.rb", 'db/migrate',
|
9
|
+
:migration_file_name => "create_delayed_jobs"
|
10
|
+
end
|
8
11
|
end
|
9
12
|
end
|
10
13
|
|
14
|
+
protected
|
15
|
+
|
16
|
+
def add_options!(opt)
|
17
|
+
opt.separator ''
|
18
|
+
opt.separator 'Options:'
|
19
|
+
opt.on("--skip-migration", "Don't generate a migration") { |v| options[:skip_migration] = v }
|
20
|
+
end
|
21
|
+
|
11
22
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require File.join(File.dirname(__FILE__), *%w(.. vendor plugins delayed_job lib delayed command))
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment'))
|
4
|
+
require 'delayed/command'
|
7
5
|
Delayed::Command.new(ARGV).daemonize
|
data/lib/delayed/command.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'rubygems'
|
2
1
|
require 'daemons'
|
3
2
|
require 'optparse'
|
4
3
|
|
@@ -44,14 +43,14 @@ module Delayed
|
|
44
43
|
|
45
44
|
def run(worker_name = nil)
|
46
45
|
Dir.chdir(RAILS_ROOT)
|
47
|
-
require File.join(RAILS_ROOT, 'config', 'environment')
|
48
46
|
|
49
|
-
# Replace the default logger
|
50
|
-
logger
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
# Replace the default logger…too bad Rails doesn't make this easier
|
48
|
+
Rails.logger.instance_eval do
|
49
|
+
@log.reopen File.join(RAILS_ROOT, 'log', 'delayed_job.log')
|
50
|
+
end
|
51
|
+
Delayed::Worker.logger = Rails.logger
|
52
|
+
ActiveRecord::Base.connection.reconnect!
|
53
|
+
|
55
54
|
Delayed::Job.worker_name = "#{worker_name} #{Delayed::Job.worker_name}"
|
56
55
|
|
57
56
|
Delayed::Worker.new(@options).start
|
@@ -6,9 +6,10 @@ module Delayed
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
def handle_asynchronously(method)
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
aliased_method, punctuation = method.to_s.sub(/([?!=])$/, ''), $1
|
10
|
+
with_method, without_method = "#{aliased_method}_with_send_later#{punctuation}", "#{aliased_method}_without_send_later#{punctuation}"
|
11
|
+
define_method(with_method) do |*args|
|
12
|
+
send_later(without_method, *args)
|
12
13
|
end
|
13
14
|
alias_method_chain method, :send_later
|
14
15
|
end
|
File without changes
|
data/lib/delayed_job.rb
CHANGED
@@ -9,5 +9,5 @@ Object.send(:include, Delayed::MessageSending)
|
|
9
9
|
Module.send(:include, Delayed::MessageSending::ClassMethods)
|
10
10
|
|
11
11
|
if defined?(Merb::Plugins)
|
12
|
-
Merb::Plugins.add_rakefiles File.dirname(__FILE__) / '
|
12
|
+
Merb::Plugins.add_rakefiles File.dirname(__FILE__) / 'delayed' / 'tasks'
|
13
13
|
end
|
data/tasks/jobs.rake
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'tasks')
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'tasks'))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: collectiveidea-delayed_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.8.
|
4
|
+
version: 1.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Tobias L\xC3\xBCtke"
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-06 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -36,6 +36,7 @@ files:
|
|
36
36
|
- lib/delayed/job.rb
|
37
37
|
- lib/delayed/message_sending.rb
|
38
38
|
- lib/delayed/performable_method.rb
|
39
|
+
- lib/delayed/tasks.rb
|
39
40
|
- lib/delayed/worker.rb
|
40
41
|
- lib/delayed_job.rb
|
41
42
|
- recipes/delayed_job.rb
|
@@ -44,9 +45,9 @@ files:
|
|
44
45
|
- spec/job_spec.rb
|
45
46
|
- spec/story_spec.rb
|
46
47
|
- tasks/jobs.rake
|
47
|
-
- tasks/tasks.rb
|
48
48
|
has_rdoc: false
|
49
49
|
homepage: http://github.com/tobi/delayed_job/tree/master
|
50
|
+
licenses:
|
50
51
|
post_install_message:
|
51
52
|
rdoc_options:
|
52
53
|
- --main
|
@@ -70,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
71
|
requirements: []
|
71
72
|
|
72
73
|
rubyforge_project:
|
73
|
-
rubygems_version: 1.
|
74
|
+
rubygems_version: 1.3.5
|
74
75
|
signing_key:
|
75
76
|
specification_version: 3
|
76
77
|
summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
|