delayed_job 3.0.4 → 3.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +153 -0
- data/CONTRIBUTING.md +18 -0
- data/{MIT-LICENSE → LICENSE.md} +1 -1
- data/{README.textile → README.md} +116 -95
- data/Rakefile +11 -0
- data/delayed_job.gemspec +17 -0
- data/lib/delayed/backend/shared_spec.rb +42 -23
- data/lib/delayed/command.rb +3 -0
- data/lib/delayed/exceptions.rb +9 -0
- data/lib/delayed/psych_ext.rb +10 -0
- data/lib/delayed/tasks.rb +16 -2
- data/lib/delayed/worker.rb +37 -19
- data/lib/delayed_job.rb +1 -0
- data/spec/message_sending_spec.rb +4 -2
- data/spec/performable_method_spec.rb +63 -16
- data/spec/worker_spec.rb +21 -0
- metadata +24 -105
data/CHANGELOG.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
3.0.5 - 2013-01-28
|
2
|
+
==================
|
3
|
+
* Better job timeout error logging
|
4
|
+
* psych support for delayed_job_data_mapper deserialization
|
5
|
+
* User can configure the worker to raise a SignalException on TERM and/or INT
|
6
|
+
* Add the ability to run all available jobs and exit when complete
|
7
|
+
|
8
|
+
3.0.4 - 2012-11-09
|
9
|
+
==================
|
10
|
+
* Allow the app to specify a default queue name
|
11
|
+
* Capistrano script now allows user to specify the DJ command, allowing the user to add "bundle exec" if necessary
|
12
|
+
* Persisted record check is now more general
|
13
|
+
|
14
|
+
3.0.3 - 2012-05-25
|
15
|
+
==================
|
16
|
+
* Fix a bug where the worker would not respect the exit condition
|
17
|
+
* Properly handle sleep delay command line argument
|
18
|
+
|
19
|
+
3.0.2 - 2012-04-02
|
20
|
+
==================
|
21
|
+
* Fix deprecation warnings
|
22
|
+
* Raise ArgumentError if attempting to enqueue a performable method on an object that hasn't been persisted yet
|
23
|
+
* Allow the number of jobs read at a time to be configured from the command line using --read-ahead
|
24
|
+
* Allow custom logger to be configured through Delayed::Worker.logger
|
25
|
+
* Various documentation improvements
|
26
|
+
|
27
|
+
3.0.1 - 2012-01-24
|
28
|
+
==================
|
29
|
+
* Added RecordNotFound message to deserialization error
|
30
|
+
* Direct JRuby's yecht parser to syck extensions
|
31
|
+
* Updated psych extensions for better compatibility with ruby 1.9.2
|
32
|
+
* Updated syck extension for increased compatibility with class methods
|
33
|
+
* Test grooming
|
34
|
+
|
35
|
+
3.0.0 - 2011-12-30
|
36
|
+
==================
|
37
|
+
* New: Named queues
|
38
|
+
* New: Job/Worker lifecycle callbacks
|
39
|
+
* Change: daemons is no longer a runtime dependency
|
40
|
+
* Change: Active Record backend support is provided by a separate gem
|
41
|
+
* Change: Enqueue hook is called before jobs are saved so that they may be modified
|
42
|
+
* Fix problem deserializing models that use a custom primary key column
|
43
|
+
* Fix deserializing AR models when the object isn't in the default scope
|
44
|
+
* Fix hooks not getting called when delay_jobs is false
|
45
|
+
|
46
|
+
2.1.4 - 2011-02-11
|
47
|
+
==================
|
48
|
+
* Working around issues when psych is loaded, fixes issues with bundler 1.0.10 and Rails 3.0.4
|
49
|
+
* Added -p/--prefix option to help differentiate multiple delayed job workers on the same host.
|
50
|
+
|
51
|
+
2.1.3 - 2011-01-20
|
52
|
+
==================
|
53
|
+
* Revert worker contention fix due to regressions
|
54
|
+
* Added Delayed::Worker.delay_jobs flag to support running jobs immediately
|
55
|
+
|
56
|
+
2.1.2 - 2010-12-01
|
57
|
+
==================
|
58
|
+
* Remove contention between multiple workers by performing an update to lock a job before fetching it
|
59
|
+
* Job payloads may implement #max_attempts to control how many times it should be retried
|
60
|
+
* Fix for loading ActionMailer extension
|
61
|
+
* Added 'delayed_job_server_role' Capistrano variable to allow delayed_job to run on its own worker server
|
62
|
+
set :delayed_job_server_role, :worker
|
63
|
+
* Fix `rake jobs:work` so it outputs to the console
|
64
|
+
|
65
|
+
2.1.1 - 2010-11-14
|
66
|
+
==================
|
67
|
+
* Fix issue with worker name not getting properly set when locking a job
|
68
|
+
* Fixes for YAML serialization
|
69
|
+
|
70
|
+
2.1.0 - 2010-11-14
|
71
|
+
==================
|
72
|
+
* Added enqueue, before, after, success, error, and failure. See the README
|
73
|
+
* Remove Merb support
|
74
|
+
* Remove all non Active Record backends into separate gems. See https://github.com/collectiveidea/delayed_job/wiki/Backends
|
75
|
+
* remove rails 2 support. delayed_job 2.1 will only support Rails 3
|
76
|
+
* New pure-YAML serialization
|
77
|
+
* Added Rails 3 railtie and generator
|
78
|
+
* Changed @@sleep_delay to self.class.sleep_delay to be consistent with other class variable usage
|
79
|
+
* Added --sleep-delay command line option
|
80
|
+
|
81
|
+
2.0.8 - Unreleased
|
82
|
+
==================
|
83
|
+
* Backport fix for deserialization errors that bring down the daemon
|
84
|
+
|
85
|
+
2.0.7 - 2011-02-10
|
86
|
+
==================
|
87
|
+
* Fixed missing generators and recipes for Rails 2.x
|
88
|
+
|
89
|
+
2.0.6 - 2011-01-20
|
90
|
+
==================
|
91
|
+
* Revert worker contention fix due to regressions
|
92
|
+
|
93
|
+
2.0.5 - 2010-12-01
|
94
|
+
==================
|
95
|
+
* Added #reschedule_at hook on payload to determine when the job should be rescheduled [backported from 2.1]
|
96
|
+
* Added --sleep-delay command line option [backported from 2.1]
|
97
|
+
* Added 'delayed_job_server_role' Capistrano variable to allow delayed_job to run on its own worker server
|
98
|
+
set :delayed_job_server_role, :worker
|
99
|
+
* Changed AR backend to reserve jobs using an UPDATE query to reduce worker contention [backported from 2.1]
|
100
|
+
|
101
|
+
2.0.4 - 2010-11-14
|
102
|
+
==================
|
103
|
+
* Fix issue where dirty tracking prevented job from being properly unlocked
|
104
|
+
* Add delayed_job_args variable for Capistrano recipe to allow configuration of started workers (e.g. "-n 2 --max-priority 10")
|
105
|
+
* Added options to handle_asynchronously
|
106
|
+
* Added Delayed::Worker.default_priority
|
107
|
+
* Allow private methods to be delayed
|
108
|
+
* Fixes for Ruby 1.9
|
109
|
+
* Added -m command line option to start a monitor process
|
110
|
+
* normalize logging in worker
|
111
|
+
* Deprecate #send_later and #send_at in favor of new #delay method
|
112
|
+
* Added @#delay@ to Object that allows you to delay any method and pass options:
|
113
|
+
options = {:priority => 19, :run_at => 5.minutes.from_now}
|
114
|
+
UserMailer.delay(options).deliver_confirmation(@user)
|
115
|
+
|
116
|
+
2.0.3 - 2010-04-16
|
117
|
+
==================
|
118
|
+
* Fix initialization for Rails 2.x
|
119
|
+
|
120
|
+
2.0.2 - 2010-04-08
|
121
|
+
==================
|
122
|
+
* Fixes to Mongo Mapper backend [ "14be7a24":http://github.com/collectiveidea/delayed_job/commit/14be7a24, "dafd5f46":http://github.com/collectiveidea/delayed_job/commit/dafd5f46, "54d40913":http://github.com/collectiveidea/delayed_job/commit/54d40913 ]
|
123
|
+
* DataMapper backend performance improvements [ "93833cce":http://github.com/collectiveidea/delayed_job/commit/93833cce, "e9b1573e":http://github.com/collectiveidea/delayed_job/commit/e9b1573e, "37a16d11":http://github.com/collectiveidea/delayed_job/commit/37a16d11, "803f2bfa":http://github.com/collectiveidea/delayed_job/commit/803f2bfa ]
|
124
|
+
* Fixed Delayed::Command to create tmp/pids directory [ "8ec8ca41":http://github.com/collectiveidea/delayed_job/commit/8ec8ca41 ]
|
125
|
+
* Railtie to perform Rails 3 initialization [ "3e0fc41f":http://github.com/collectiveidea/delayed_job/commit/3e0fc41f ]
|
126
|
+
* Added on_permanent_failure hook [ "d2f14cd6":http://github.com/collectiveidea/delayed_job/commit/d2f14cd6 ]
|
127
|
+
|
128
|
+
2.0.1 - 2010-04-03
|
129
|
+
==================
|
130
|
+
* Bug fix for using ActiveRecord backend with daemon [martinbtt]
|
131
|
+
|
132
|
+
2.0.0 - 2010-04-03
|
133
|
+
==================
|
134
|
+
* Multiple backend support (See README for more details)
|
135
|
+
* Added MongoMapper backend [zbelzer, moneypools]
|
136
|
+
* Added DataMapper backend [lpetre]
|
137
|
+
* Reverse priority so the jobs table can be indexed. Lower numbers have higher priority. The default priority is 0, so increase it for jobs that are not important.
|
138
|
+
* Move most of the heavy lifting from Job to Worker (#work_off, #reschedule, #run, #min_priority, #max_priority, #max_run_time, #max_attempts, #worker_name) [albus522]
|
139
|
+
* Remove EvaledJob. Implement your own if you need this functionality.
|
140
|
+
* Only use Time.zone if it is set. Closes #20
|
141
|
+
* Fix for last_error recording when destroy_failed_jobs = false, max_attempts = 1
|
142
|
+
* Implemented worker name_prefix to maintain dynamic nature of pid detection
|
143
|
+
* Some Rails 3 compatibility fixes [fredwu]
|
144
|
+
|
145
|
+
1.8.5 - 2010-03-15
|
146
|
+
==================
|
147
|
+
* Set auto_flushing=true on Rails logger to fix logging in production
|
148
|
+
* Fix error message when trying to send_later on a method that doesn't exist
|
149
|
+
* Don't use rails_env in capistrano if it's not set. closes #22
|
150
|
+
* Delayed job should append to delayed_job.log not overwrite
|
151
|
+
* Version bump to 1.8.5
|
152
|
+
* fixing Time.now to be Time.zone.now if set to honor the app set local TimeZone
|
153
|
+
* Replaced @Worker::SLEEP@, @Job::MAX_ATTEMPTS@, and @Job::MAX_RUN_TIME@ with class methods that can be overridden.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
How to contribute
|
2
|
+
=================
|
3
|
+
|
4
|
+
If you find what looks like a bug:
|
5
|
+
|
6
|
+
* Search the "mailing list":http://groups.google.com/group/delayed_job to see
|
7
|
+
if anyone else had the same issue.
|
8
|
+
* Check the "GitHub issue tracker":http://github.com/collectiveidea/delayed_job/issues/
|
9
|
+
to see if anyone else has reported issue.
|
10
|
+
* If you don't see anything, create an issue with information on how to reproduce it.
|
11
|
+
|
12
|
+
If you want to contribute an enhancement or a fix:
|
13
|
+
|
14
|
+
* Fork the project on GitHub.
|
15
|
+
* Make your changes with tests.
|
16
|
+
* Commit the changes without making changes to the Rakefile or any other files
|
17
|
+
that aren't related to your enhancement or fix.
|
18
|
+
* Send a pull request.
|
data/{MIT-LICENSE → LICENSE.md}
RENAMED
@@ -1,8 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
Delayed::Job
|
2
|
+
============
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/delayed_job.png)][gem]
|
4
|
+
[![Build Status](https://secure.travis-ci.org/collectiveidea/delayed_job.png?branch=master)][travis]
|
5
|
+
[![Dependency Status](https://gemnasium.com/collectiveidea/delayed_job.png?travis)][gemnasium]
|
6
|
+
[![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
|
7
|
+
[gem]: https://rubygems.org/gems/delayed_job
|
8
|
+
[travis]: http://travis-ci.org/collectiveidea/delayed_job
|
9
|
+
[gemnasium]: https://gemnasium.com/collectiveidea/delayed_job
|
10
|
+
[codeclimate]: https://codeclimate.com/github/collectiveidea/delayed_job
|
11
|
+
|
12
|
+
Delayed::Job (or DJ) encapsulates the common pattern of asynchronously executing
|
13
|
+
longer tasks in the background.
|
14
|
+
|
15
|
+
It is a direct extraction from Shopify where the job table is responsible for a
|
16
|
+
multitude of core tasks. Amongst those tasks are:
|
6
17
|
|
7
18
|
* sending massive newsletters
|
8
19
|
* image resizing
|
@@ -12,61 +23,57 @@ It is a direct extraction from Shopify where the job table is responsible for a
|
|
12
23
|
* batch imports
|
13
24
|
* spam checks
|
14
25
|
|
15
|
-
|
26
|
+
[Follow us on Twitter][twitter] to get updates and notices about new releases.
|
16
27
|
|
17
|
-
|
28
|
+
[twitter]: https://twitter.com/delayedjob
|
18
29
|
|
19
|
-
|
30
|
+
Installation
|
31
|
+
============
|
32
|
+
delayed_job 3.0.0 only supports Rails 3.0+. See the [2.0
|
33
|
+
branch](https://github.com/collectiveidea/delayed_job/tree/v2.0) for Rails 2.
|
20
34
|
|
21
|
-
delayed_job supports multiple backends for storing the job queue.
|
35
|
+
delayed_job supports multiple backends for storing the job queue. [See the wiki
|
36
|
+
for other backends](http://wiki.github.com/collectiveidea/delayed_job/backends).
|
22
37
|
|
23
|
-
If you plan to use delayed_job with Active Record, add
|
38
|
+
If you plan to use delayed_job with Active Record, add `delayed_job_active_record` to your `Gemfile`.
|
24
39
|
|
25
|
-
|
26
|
-
gem 'delayed_job_active_record'
|
27
|
-
</pre>
|
40
|
+
gem 'delayed_job_active_record'
|
28
41
|
|
29
|
-
If you plan to use delayed_job with Mongoid, add
|
42
|
+
If you plan to use delayed_job with Mongoid, add `delayed_job_mongoid` to your `Gemfile`.
|
30
43
|
|
31
|
-
|
32
|
-
gem 'delayed_job_mongoid'
|
33
|
-
</pre>
|
44
|
+
gem 'delayed_job_mongoid'
|
34
45
|
|
35
|
-
Run
|
46
|
+
Run `bundle install` to install the backend and delayed_job gems.
|
36
47
|
|
37
|
-
The Active Record backend requires a jobs table. You can create that table by
|
48
|
+
The Active Record backend requires a jobs table. You can create that table by
|
49
|
+
running the following command:
|
38
50
|
|
39
|
-
|
40
|
-
|
41
|
-
$ rake db:migrate
|
42
|
-
</pre>
|
43
|
-
|
44
|
-
h3. Upgrading from 2.x to 3.0.0 on Active Record
|
51
|
+
rails generate delayed_job:active_record
|
52
|
+
rake db:migrate
|
45
53
|
|
54
|
+
Upgrading from 2.x to 3.0.0 on Active Record
|
55
|
+
============================================
|
46
56
|
Delayed Job 3.0.0 introduces a new column to the delayed_jobs table.
|
47
57
|
|
48
58
|
If you're upgrading from Delayed Job 2.x, run the upgrade generator to create a migration to add the column.
|
49
59
|
|
50
|
-
|
51
|
-
|
52
|
-
$ rake db:migrate
|
53
|
-
</pre>
|
60
|
+
rails generate delayed_job:upgrade
|
61
|
+
rake db:migrate
|
54
62
|
|
55
|
-
|
63
|
+
Queuing Jobs
|
64
|
+
============
|
65
|
+
Call `.delay.method(params)` on any object and it will be processed in the background.
|
56
66
|
|
57
|
-
|
67
|
+
# without delayed_job
|
68
|
+
@user.activate!(@device)
|
58
69
|
|
59
|
-
|
60
|
-
|
61
|
-
@user.activate!(@device)
|
70
|
+
# with delayed_job
|
71
|
+
@user.delay.activate!(@device)
|
62
72
|
|
63
|
-
|
64
|
-
|
65
|
-
</pre>
|
66
|
-
|
67
|
-
If a method should always be run in the background, you can call @#handle_asynchronously@ after the method declaration:
|
73
|
+
If a method should always be run in the background, you can call
|
74
|
+
`#handle_asynchronously` after the method declaration:
|
68
75
|
|
69
|
-
|
76
|
+
```ruby
|
70
77
|
class Device
|
71
78
|
def deliver
|
72
79
|
# long running method
|
@@ -76,11 +83,13 @@ end
|
|
76
83
|
|
77
84
|
device = Device.new
|
78
85
|
device.deliver
|
79
|
-
|
86
|
+
```
|
80
87
|
|
81
|
-
handle_asynchronously can take as options anything you can pass to delay. In
|
88
|
+
handle_asynchronously can take as options anything you can pass to delay. In
|
89
|
+
addition, the values can be Proc objects allowing call time evaluation of the
|
90
|
+
value. For some examples:
|
82
91
|
|
83
|
-
|
92
|
+
```ruby
|
84
93
|
class LongTasks
|
85
94
|
def send_mailer
|
86
95
|
# Some other code
|
@@ -109,72 +118,84 @@ class LongTasks
|
|
109
118
|
end
|
110
119
|
handle_asynchronously :call_an_instance_method, :priority => Proc.new {|i| i.how_important }
|
111
120
|
end
|
112
|
-
|
113
|
-
|
114
|
-
h3. Rails 3 Mailers
|
121
|
+
```
|
115
122
|
|
123
|
+
Rails 3 Mailers
|
124
|
+
===============
|
116
125
|
Due to how mailers are implemented in Rails 3, we had to do a little work around to get delayed_job to work.
|
117
126
|
|
118
|
-
|
127
|
+
```ruby
|
119
128
|
# without delayed_job
|
120
129
|
Notifier.signup(@user).deliver
|
121
130
|
|
122
131
|
# with delayed_job
|
123
132
|
Notifier.delay.signup(@user)
|
124
|
-
|
133
|
+
```
|
125
134
|
|
126
|
-
Remove the
|
135
|
+
Remove the `.deliver` method to make it work. It's not ideal, but it's the best
|
136
|
+
we could do for now.
|
127
137
|
|
128
|
-
|
138
|
+
Named Queues
|
139
|
+
============
|
140
|
+
DJ 3 introduces Resque-style named queues while still retaining DJ-style
|
141
|
+
priority. The goal is to provide a system for grouping tasks to be worked by
|
142
|
+
separate pools of workers, which may be scaled and controlled individually.
|
129
143
|
|
130
|
-
|
144
|
+
Jobs can be assigned to a queue by setting the `queue` option:
|
131
145
|
|
132
|
-
|
133
|
-
|
134
|
-
<pre>object.delay(:queue => 'tracking').method
|
146
|
+
```ruby
|
147
|
+
object.delay(:queue => 'tracking').method
|
135
148
|
|
136
149
|
Delayed::Job.enqueue job, :queue => 'tracking'
|
137
150
|
|
138
151
|
handle_asynchronously :tweet_later, :queue => 'tweets'
|
139
|
-
|
140
|
-
|
141
|
-
h2. Running Jobs
|
152
|
+
```
|
142
153
|
|
143
|
-
|
154
|
+
Running Jobs
|
155
|
+
============
|
156
|
+
`script/delayed_job` can be used to manage a background process which will
|
157
|
+
start working off jobs.
|
144
158
|
|
145
|
-
To do so, add
|
159
|
+
To do so, add `gem "daemons"` to your `Gemfile` and make sure you've run `rails
|
160
|
+
generate delayed_job`.
|
146
161
|
|
147
162
|
You can then do the following:
|
148
163
|
|
149
|
-
|
150
|
-
|
151
|
-
$ RAILS_ENV=production script/delayed_job stop
|
164
|
+
RAILS_ENV=production script/delayed_job start
|
165
|
+
RAILS_ENV=production script/delayed_job stop
|
152
166
|
|
153
|
-
# Runs two workers in separate processes.
|
154
|
-
|
155
|
-
|
167
|
+
# Runs two workers in separate processes.
|
168
|
+
RAILS_ENV=production script/delayed_job -n 2 start
|
169
|
+
RAILS_ENV=production script/delayed_job stop
|
156
170
|
|
157
|
-
# Set the --queue or --queues option to work from a particular queue.
|
158
|
-
|
159
|
-
|
160
|
-
</pre>
|
171
|
+
# Set the --queue or --queues option to work from a particular queue.
|
172
|
+
RAILS_ENV=production script/delayed_job --queue=tracking start
|
173
|
+
RAILS_ENV=production script/delayed_job --queues=mailers,tasks start
|
161
174
|
|
162
|
-
|
175
|
+
# Runs all available jobs and the exits
|
176
|
+
RAILS_ENV=production script/delayed_job start --exit-on-complete
|
177
|
+
# or to run in the foreground
|
178
|
+
RAILS_ENV=production script/delayed_job run --exit-on-complete
|
163
179
|
|
164
|
-
|
180
|
+
Workers can be running on any computer, as long as they have access to the
|
181
|
+
database and their clock is in sync. Keep in mind that each worker will check
|
182
|
+
the database at least every 5 seconds.
|
165
183
|
|
166
|
-
|
184
|
+
You can also invoke `rake jobs:work` which will start working off jobs. You can
|
185
|
+
cancel the rake task with `CTRL-C`.
|
167
186
|
|
168
|
-
|
169
|
-
QUEUE=tracking rake jobs:work
|
170
|
-
QUEUES=mailers,tasks rake jobs:work
|
171
|
-
</pre>
|
187
|
+
If you want to just run all available jobs and exit you can use `rake jobs:workoff`
|
172
188
|
|
173
|
-
|
189
|
+
Work off queues by setting the `QUEUE` or `QUEUES` environment variable.
|
174
190
|
|
191
|
+
QUEUE=tracking rake jobs:work
|
192
|
+
QUEUES=mailers,tasks rake jobs:work
|
193
|
+
|
194
|
+
Custom Jobs
|
195
|
+
===========
|
175
196
|
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.
|
176
197
|
|
177
|
-
|
198
|
+
```ruby
|
178
199
|
class NewsletterJob < Struct.new(:text, :emails)
|
179
200
|
def perform
|
180
201
|
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
@@ -182,13 +203,13 @@ class NewsletterJob < Struct.new(:text, :emails)
|
|
182
203
|
end
|
183
204
|
|
184
205
|
Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
|
185
|
-
|
186
|
-
|
187
|
-
h2. Hooks
|
206
|
+
```
|
188
207
|
|
208
|
+
Hooks
|
209
|
+
=====
|
189
210
|
You can define hooks on your job that will be called at different stages in the process:
|
190
211
|
|
191
|
-
|
212
|
+
```ruby
|
192
213
|
class ParanoidNewsletterJob < NewsletterJob
|
193
214
|
def enqueue(job)
|
194
215
|
record_stat 'newsletter_job/enqueue'
|
@@ -218,13 +239,13 @@ class ParanoidNewsletterJob < NewsletterJob
|
|
218
239
|
page_sysadmin_in_the_middle_of_the_night
|
219
240
|
end
|
220
241
|
end
|
221
|
-
|
222
|
-
|
223
|
-
h2. Gory Details
|
242
|
+
```
|
224
243
|
|
244
|
+
Gory Details
|
245
|
+
============
|
225
246
|
The library revolves around a delayed_jobs table which looks as follows:
|
226
247
|
|
227
|
-
|
248
|
+
```ruby
|
228
249
|
create_table :delayed_jobs, :force => true do |table|
|
229
250
|
table.integer :priority, :default => 0 # Allows some jobs to jump to the front of the queue
|
230
251
|
table.integer :attempts, :default => 0 # Provides for retries, but still fail eventually.
|
@@ -237,7 +258,7 @@ create_table :delayed_jobs, :force => true do |table|
|
|
237
258
|
table.string :queue # The name of the queue this job is in
|
238
259
|
table.timestamps
|
239
260
|
end
|
240
|
-
|
261
|
+
```
|
241
262
|
|
242
263
|
On failure, the job is scheduled again in 5 seconds + N ** 4, where N is the number of retries.
|
243
264
|
|
@@ -258,7 +279,7 @@ It is possible to disable delayed jobs for testing purposes. Set Delayed::Worker
|
|
258
279
|
|
259
280
|
Here is an example of changing job parameters in Rails:
|
260
281
|
|
261
|
-
|
282
|
+
```ruby
|
262
283
|
# config/initializers/delayed_job_config.rb
|
263
284
|
Delayed::Worker.destroy_failed_jobs = false
|
264
285
|
Delayed::Worker.sleep_delay = 60
|
@@ -266,12 +287,12 @@ Delayed::Worker.max_attempts = 3
|
|
266
287
|
Delayed::Worker.max_run_time = 5.minutes
|
267
288
|
Delayed::Worker.read_ahead = 10
|
268
289
|
Delayed::Worker.delay_jobs = !Rails.env.test?
|
269
|
-
|
270
|
-
|
271
|
-
h3. Cleaning up
|
272
|
-
|
273
|
-
You can invoke @rake jobs:clear@ to delete all jobs in the queue.
|
290
|
+
```
|
274
291
|
|
275
|
-
|
292
|
+
Cleaning up
|
293
|
+
===========
|
294
|
+
You can invoke `rake jobs:clear` to delete all jobs in the queue.
|
276
295
|
|
277
|
-
|
296
|
+
Mailing List
|
297
|
+
============
|
298
|
+
Join us on the [mailing list](http://groups.google.com/group/delayed_job)
|
data/Rakefile
ADDED
data/delayed_job.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.add_dependency 'activesupport', '~> 3.0'
|
5
|
+
spec.authors = ["Brandon Keepers", "Brian Ryckbost", "Chris Gaffney", "David Genord II", "Erik Michaels-Ober", "Matt Griffin", "Steve Richert", "Tobias Lütke"]
|
6
|
+
spec.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."
|
7
|
+
spec.email = ['brian@collectiveidea.com']
|
8
|
+
spec.files = %w(CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md Rakefile delayed_job.gemspec)
|
9
|
+
spec.files += Dir.glob('{contrib,lib,recipes,spec}/**/*')
|
10
|
+
spec.homepage = 'http://github.com/collectiveidea/delayed_job'
|
11
|
+
spec.licenses = ['MIT']
|
12
|
+
spec.name = 'delayed_job'
|
13
|
+
spec.require_paths = ['lib']
|
14
|
+
spec.summary = 'Database-backed asynchronous priority queue system -- Extracted from Shopify'
|
15
|
+
spec.test_files = Dir.glob('spec/**/*')
|
16
|
+
spec.version = '3.0.5'
|
17
|
+
end
|
@@ -18,6 +18,10 @@ shared_examples_for "a delayed_job backend" do
|
|
18
18
|
described_class.delete_all
|
19
19
|
end
|
20
20
|
|
21
|
+
after do
|
22
|
+
Delayed::Worker.reset
|
23
|
+
end
|
24
|
+
|
21
25
|
it "sets run_at automatically if not set" do
|
22
26
|
expect(described_class.create(:payload_object => ErrorJob.new ).run_at).not_to be_nil
|
23
27
|
end
|
@@ -181,6 +185,10 @@ shared_examples_for "a delayed_job backend" do
|
|
181
185
|
Delayed::Worker.max_run_time = 2.minutes
|
182
186
|
end
|
183
187
|
|
188
|
+
after do
|
189
|
+
Time.zone = nil
|
190
|
+
end
|
191
|
+
|
184
192
|
it "does not reserve failed jobs" do
|
185
193
|
create_job :attempts => 50, :failed_at => described_class.db_time_now
|
186
194
|
expect(described_class.reserve(worker)).to be_nil
|
@@ -249,7 +257,7 @@ shared_examples_for "a delayed_job backend" do
|
|
249
257
|
end
|
250
258
|
|
251
259
|
context "worker prioritization" do
|
252
|
-
|
260
|
+
after do
|
253
261
|
Delayed::Worker.max_priority = nil
|
254
262
|
Delayed::Worker.min_priority = nil
|
255
263
|
end
|
@@ -267,15 +275,25 @@ shared_examples_for "a delayed_job backend" do
|
|
267
275
|
it "only finds jobs greater than or equal to min priority" do
|
268
276
|
min = 5
|
269
277
|
Delayed::Worker.min_priority = min
|
270
|
-
|
271
|
-
|
278
|
+
[4,5,6].sort_by {|i| rand }.each {|i| create_job :priority => i }
|
279
|
+
2.times do
|
280
|
+
job = described_class.reserve(worker)
|
281
|
+
expect(job.priority).to be >= min
|
282
|
+
job.destroy
|
283
|
+
end
|
284
|
+
expect(described_class.reserve(worker)).to be_nil
|
272
285
|
end
|
273
286
|
|
274
287
|
it "only finds jobs less than or equal to max priority" do
|
275
288
|
max = 5
|
276
289
|
Delayed::Worker.max_priority = max
|
277
|
-
|
278
|
-
|
290
|
+
[4,5,6].sort_by {|i| rand }.each {|i| create_job :priority => i }
|
291
|
+
2.times do
|
292
|
+
job = described_class.reserve(worker)
|
293
|
+
expect(job.priority).to be <= max
|
294
|
+
job.destroy
|
295
|
+
end
|
296
|
+
expect(described_class.reserve(worker)).to be_nil
|
279
297
|
end
|
280
298
|
end
|
281
299
|
|
@@ -421,19 +439,19 @@ shared_examples_for "a delayed_job backend" do
|
|
421
439
|
|
422
440
|
describe "running a job" do
|
423
441
|
it "fails after Worker.max_run_time" do
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
expect(job.attempts).to eq(1)
|
431
|
-
ensure
|
432
|
-
Delayed::Worker.max_run_time = old_max_run_time
|
433
|
-
end
|
442
|
+
Delayed::Worker.max_run_time = 1.second
|
443
|
+
job = Delayed::Job.create :payload_object => LongRunningJob.new
|
444
|
+
worker.run(job)
|
445
|
+
expect(job.reload.last_error).to match(/expired/)
|
446
|
+
expect(job.reload.last_error).to match(/Delayed::Worker.max_run_time is only 1 second/)
|
447
|
+
expect(job.attempts).to eq(1)
|
434
448
|
end
|
435
449
|
|
436
450
|
context "when the job raises a deserialization error" do
|
451
|
+
after do
|
452
|
+
Delayed::Worker.destroy_failed_jobs = true
|
453
|
+
end
|
454
|
+
|
437
455
|
it "marks the job as failed" do
|
438
456
|
Delayed::Worker.destroy_failed_jobs = false
|
439
457
|
job = described_class.create! :handler => "--- !ruby/object:JobThatDoesNotExist {}"
|
@@ -446,11 +464,12 @@ shared_examples_for "a delayed_job backend" do
|
|
446
464
|
|
447
465
|
describe "failed jobs" do
|
448
466
|
before do
|
449
|
-
|
450
|
-
|
451
|
-
Delayed::Worker.max_attempts = 25
|
467
|
+
@job = Delayed::Job.enqueue(ErrorJob.new, :run_at => described_class.db_time_now - 1)
|
468
|
+
end
|
452
469
|
|
453
|
-
|
470
|
+
after do
|
471
|
+
# reset default
|
472
|
+
Delayed::Worker.destroy_failed_jobs = true
|
454
473
|
end
|
455
474
|
|
456
475
|
it "records last_error when destroy_failed_jobs = false, max_attempts = 1" do
|
@@ -535,10 +554,6 @@ shared_examples_for "a delayed_job backend" do
|
|
535
554
|
end
|
536
555
|
|
537
556
|
context "and we want to destroy jobs" do
|
538
|
-
before do
|
539
|
-
Delayed::Worker.destroy_failed_jobs = true
|
540
|
-
end
|
541
|
-
|
542
557
|
it_should_behave_like "any failure more than Worker.max_attempts times"
|
543
558
|
|
544
559
|
it "is destroyed if it failed more than Worker.max_attempts times" do
|
@@ -557,6 +572,10 @@ shared_examples_for "a delayed_job backend" do
|
|
557
572
|
Delayed::Worker.destroy_failed_jobs = false
|
558
573
|
end
|
559
574
|
|
575
|
+
after do
|
576
|
+
Delayed::Worker.destroy_failed_jobs = true
|
577
|
+
end
|
578
|
+
|
560
579
|
it_should_behave_like "any failure more than Worker.max_attempts times"
|
561
580
|
|
562
581
|
it "is failed if it failed more than Worker.max_attempts times" do
|
data/lib/delayed/command.rb
CHANGED
@@ -61,6 +61,9 @@ module Delayed
|
|
61
61
|
opts.on('--queue=queue', "Specify which queue DJ must look up for jobs") do |queue|
|
62
62
|
@options[:queues] = queue.split(',')
|
63
63
|
end
|
64
|
+
opts.on('--exit-on-complete', "Exit when no more jobs are available to run. This will exit if all jobs are scheduled to run in the future.") do
|
65
|
+
@options[:exit_on_complete] = true
|
66
|
+
end
|
64
67
|
end
|
65
68
|
@args = opts.parse!(args)
|
66
69
|
end
|
data/lib/delayed/psych_ext.rb
CHANGED
@@ -111,6 +111,16 @@ module Psych
|
|
111
111
|
rescue Mongoid::Errors::DocumentNotFound
|
112
112
|
raise Delayed::DeserializationError
|
113
113
|
end
|
114
|
+
when /^!ruby\/DataMapper:(.+)$/
|
115
|
+
klass = resolve_class($1)
|
116
|
+
payload = Hash[*object.children.map { |c| accept c }]
|
117
|
+
begin
|
118
|
+
primary_keys = klass.properties.select { |p| p.key? }
|
119
|
+
key_names = primary_keys.map { |p| p.name.to_s }
|
120
|
+
klass.get!(*key_names.map { |k| payload["attributes"][k] })
|
121
|
+
rescue DataMapper::ObjectNotFoundError
|
122
|
+
raise Delayed::DeserializationError
|
123
|
+
end
|
114
124
|
else
|
115
125
|
visit_Psych_Nodes_Mapping_without_class(object)
|
116
126
|
end
|
data/lib/delayed/tasks.rb
CHANGED
@@ -5,7 +5,21 @@ namespace :jobs do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
desc "Start a delayed_job worker."
|
8
|
-
task :work => :
|
9
|
-
Delayed::Worker.new(
|
8
|
+
task :work => :environment_options do
|
9
|
+
Delayed::Worker.new(@worker_options).start
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Start a delayed_job worker and exit when all available jobs are complete."
|
13
|
+
task :workoff => :environment_options do
|
14
|
+
Delayed::Worker.new(@worker_options.merge({:exit_on_complete => true})).start
|
15
|
+
end
|
16
|
+
|
17
|
+
task :environment_options => :environment do
|
18
|
+
@worker_options = {
|
19
|
+
:min_priority => ENV['MIN_PRIORITY'],
|
20
|
+
:max_priority => ENV['MAX_PRIORITY'],
|
21
|
+
:queues => (ENV['QUEUES'] || ENV['QUEUE'] || '').split(','),
|
22
|
+
:quiet => false
|
23
|
+
}
|
10
24
|
end
|
11
25
|
end
|
data/lib/delayed/worker.rb
CHANGED
@@ -18,7 +18,7 @@ module Delayed
|
|
18
18
|
|
19
19
|
cattr_accessor :min_priority, :max_priority, :max_attempts, :max_run_time,
|
20
20
|
:default_priority, :sleep_delay, :logger, :delay_jobs, :queues,
|
21
|
-
:read_ahead, :plugins, :destroy_failed_jobs
|
21
|
+
:read_ahead, :plugins, :destroy_failed_jobs, :exit_on_complete
|
22
22
|
|
23
23
|
# Named queue into which jobs are enqueued by default
|
24
24
|
cattr_accessor :default_queue_name
|
@@ -47,6 +47,15 @@ module Delayed
|
|
47
47
|
# (perhaps to inspect the reason for the failure), set this to false.
|
48
48
|
self.destroy_failed_jobs = true
|
49
49
|
|
50
|
+
# By default, Signals INT and TERM set @exit, and the worker exits upon completion of the current job.
|
51
|
+
# If you would prefer to raise a SignalException and exit immediately you can use this.
|
52
|
+
# Be aware daemons uses TERM to stop and restart
|
53
|
+
# false - No exceptions will be raised
|
54
|
+
# :term - Will only raise an exception on TERM signals but INT will wait for the current job to finish
|
55
|
+
# true - Will raise an exception on TERM and INT
|
56
|
+
cattr_accessor :raise_signal_exceptions
|
57
|
+
self.raise_signal_exceptions = false
|
58
|
+
|
50
59
|
self.logger = if defined?(Rails)
|
51
60
|
Rails.logger
|
52
61
|
elsif defined?(RAILS_DEFAULT_LOGGER)
|
@@ -97,11 +106,10 @@ module Delayed
|
|
97
106
|
|
98
107
|
def initialize(options={})
|
99
108
|
@quiet = options.has_key?(:quiet) ? options[:quiet] : true
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
self.class.queues = options[:queues] if options.has_key?(:queues)
|
109
|
+
|
110
|
+
[:min_priority, :max_priority, :sleep_delay, :read_ahead, :queues, :exit_on_complete].each do |option|
|
111
|
+
self.class.send("#{option}=", options[option]) if options.has_key?(option)
|
112
|
+
end
|
105
113
|
|
106
114
|
self.plugins.each { |klass| klass.new }
|
107
115
|
end
|
@@ -122,29 +130,39 @@ module Delayed
|
|
122
130
|
end
|
123
131
|
|
124
132
|
def start
|
125
|
-
trap('TERM')
|
126
|
-
|
133
|
+
trap('TERM') do
|
134
|
+
say 'Exiting...'
|
135
|
+
stop
|
136
|
+
raise SignalException.new('TERM') if self.class.raise_signal_exceptions
|
137
|
+
end
|
138
|
+
|
139
|
+
trap('INT') do
|
140
|
+
say 'Exiting...'
|
141
|
+
stop
|
142
|
+
raise SignalException.new('INT') if self.class.raise_signal_exceptions && self.class.raise_signal_exceptions != :term
|
143
|
+
end
|
127
144
|
|
128
145
|
say "Starting job worker"
|
129
146
|
|
130
147
|
self.class.lifecycle.run_callbacks(:execute, self) do
|
131
148
|
loop do
|
132
149
|
self.class.lifecycle.run_callbacks(:loop, self) do
|
133
|
-
|
134
|
-
|
135
|
-
realtime = Benchmark.realtime do
|
136
|
-
result = work_off
|
150
|
+
@realtime = Benchmark.realtime do
|
151
|
+
@result = work_off
|
137
152
|
end
|
153
|
+
end
|
138
154
|
|
139
|
-
|
140
|
-
|
141
|
-
break if stop?
|
155
|
+
count = @result.sum
|
142
156
|
|
143
|
-
|
144
|
-
|
157
|
+
if count.zero?
|
158
|
+
if self.class.exit_on_complete
|
159
|
+
say "No more jobs available. Exiting"
|
160
|
+
break
|
145
161
|
else
|
146
|
-
|
162
|
+
sleep(self.class.sleep_delay) unless stop?
|
147
163
|
end
|
164
|
+
else
|
165
|
+
say "#{count} jobs processed at %.4f j/s, %d failed ..." % [count / @realtime, @result.last]
|
148
166
|
end
|
149
167
|
|
150
168
|
break if stop?
|
@@ -182,7 +200,7 @@ module Delayed
|
|
182
200
|
|
183
201
|
def run(job)
|
184
202
|
runtime = Benchmark.realtime do
|
185
|
-
Timeout.timeout(self.class.max_run_time.to_i) { job.invoke_job }
|
203
|
+
Timeout.timeout(self.class.max_run_time.to_i, WorkerTimeout) { job.invoke_job }
|
186
204
|
job.destroy
|
187
205
|
end
|
188
206
|
say "#{job.name} completed after %.4f" % runtime
|
data/lib/delayed_job.rb
CHANGED
@@ -67,6 +67,10 @@ describe Delayed::MessageSending do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
+
after do
|
71
|
+
Delayed::Worker.default_queue_name = nil
|
72
|
+
end
|
73
|
+
|
70
74
|
it "creates a new PerformableMethod job" do
|
71
75
|
expect {
|
72
76
|
job = "hello".delay.count('l')
|
@@ -80,14 +84,12 @@ describe Delayed::MessageSending do
|
|
80
84
|
Delayed::Worker.default_priority = 99
|
81
85
|
job = FairyTail.delay.to_s
|
82
86
|
expect(job.priority).to eq(99)
|
83
|
-
Delayed::Worker.default_priority = 0
|
84
87
|
end
|
85
88
|
|
86
89
|
it "sets default queue name" do
|
87
90
|
Delayed::Worker.default_queue_name = 'abbazabba'
|
88
91
|
job = FairyTail.delay.to_s
|
89
92
|
expect(job.queue).to eq('abbazabba')
|
90
|
-
Delayed::Worker.default_queue_name = nil
|
91
93
|
end
|
92
94
|
|
93
95
|
it "sets job options" do
|
@@ -40,36 +40,44 @@ describe Delayed::PerformableMethod do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
describe "hooks" do
|
43
|
-
%w(
|
43
|
+
%w(before after success).each do |hook|
|
44
44
|
it "delegates #{hook} hook to object" do
|
45
45
|
story = Story.create
|
46
|
-
story.
|
47
|
-
|
46
|
+
job = story.delay.tell
|
47
|
+
|
48
|
+
story.should_receive(hook).with(job)
|
49
|
+
job.invoke_job
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
51
53
|
%w(before after success).each do |hook|
|
52
|
-
it "delegates #{hook} hook to object
|
53
|
-
Delayed::Worker.delay_jobs = false
|
54
|
+
it "delegates #{hook} hook to object" do
|
54
55
|
story = Story.create
|
55
|
-
story.
|
56
|
-
|
56
|
+
job = story.delay.tell
|
57
|
+
|
58
|
+
story.should_receive(hook).with(job)
|
59
|
+
job.invoke_job
|
57
60
|
end
|
58
61
|
end
|
59
62
|
|
63
|
+
it "delegates enqueue hook to object" do
|
64
|
+
story = Story.create
|
65
|
+
story.should_receive(:enqueue).with(an_instance_of(Delayed::Job))
|
66
|
+
story.delay.tell
|
67
|
+
end
|
68
|
+
|
60
69
|
it "delegates error hook to object" do
|
61
70
|
story = Story.create
|
62
71
|
story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
63
72
|
story.should_receive(:tell).and_raise(RuntimeError)
|
64
|
-
expect{story.delay.tell.invoke_job}.to raise_error
|
73
|
+
expect { story.delay.tell.invoke_job }.to raise_error
|
65
74
|
end
|
66
75
|
|
67
76
|
it "delegates error hook to object when delay_jobs = false" do
|
68
|
-
Delayed::Worker.delay_jobs = false
|
69
77
|
story = Story.create
|
70
78
|
story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
71
79
|
story.should_receive(:tell).and_raise(RuntimeError)
|
72
|
-
expect{story.delay.tell}.to raise_error
|
80
|
+
expect { story.delay.tell.invoke_job }.to raise_error
|
73
81
|
end
|
74
82
|
|
75
83
|
it "delegates failure hook to object" do
|
@@ -78,12 +86,51 @@ describe Delayed::PerformableMethod do
|
|
78
86
|
method.failure
|
79
87
|
end
|
80
88
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
method.failure
|
86
|
-
end
|
89
|
+
context 'with delay_job == false' do
|
90
|
+
before do
|
91
|
+
Delayed::Worker.delay_jobs = false
|
92
|
+
end
|
87
93
|
|
94
|
+
after do
|
95
|
+
Delayed::Worker.delay_jobs = true
|
96
|
+
end
|
97
|
+
|
98
|
+
%w(before after success).each do |hook|
|
99
|
+
it "delegates #{hook} hook to object" do
|
100
|
+
story = Story.create
|
101
|
+
story.should_receive(hook).with(an_instance_of(Delayed::Job))
|
102
|
+
story.delay.tell
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
%w(before after success).each do |hook|
|
107
|
+
it "delegates #{hook} hook to object" do
|
108
|
+
story = Story.create
|
109
|
+
story.should_receive(hook).with(an_instance_of(Delayed::Job))
|
110
|
+
story.delay.tell
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "delegates error hook to object" do
|
115
|
+
story = Story.create
|
116
|
+
story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
117
|
+
story.should_receive(:tell).and_raise(RuntimeError)
|
118
|
+
expect { story.delay.tell }.to raise_error
|
119
|
+
end
|
120
|
+
|
121
|
+
it "delegates error hook to object when delay_jobs = false" do
|
122
|
+
story = Story.create
|
123
|
+
story.should_receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
124
|
+
story.should_receive(:tell).and_raise(RuntimeError)
|
125
|
+
expect { story.delay.tell }.to raise_error
|
126
|
+
end
|
127
|
+
|
128
|
+
it "delegates failure hook to object when delay_jobs = false" do
|
129
|
+
Delayed::Worker.delay_jobs = false
|
130
|
+
method = Delayed::PerformableMethod.new("object", :size, [])
|
131
|
+
method.object.should_receive(:failure)
|
132
|
+
method.failure
|
133
|
+
end
|
134
|
+
end
|
88
135
|
end
|
89
136
|
end
|
data/spec/worker_spec.rb
CHANGED
@@ -7,6 +7,10 @@ describe Delayed::Worker do
|
|
7
7
|
Delayed::Worker.backend = @clazz
|
8
8
|
end
|
9
9
|
|
10
|
+
after do
|
11
|
+
Delayed::Worker.backend = :test
|
12
|
+
end
|
13
|
+
|
10
14
|
it "sets the Delayed::Job constant to the backend" do
|
11
15
|
expect(Delayed::Job).to eq(@clazz)
|
12
16
|
end
|
@@ -37,4 +41,21 @@ describe Delayed::Worker do
|
|
37
41
|
Delayed::Job.reserve(Delayed::Worker.new)
|
38
42
|
end
|
39
43
|
end
|
44
|
+
|
45
|
+
context "worker exit on complete" do
|
46
|
+
before do
|
47
|
+
Delayed::Worker.exit_on_complete = true
|
48
|
+
end
|
49
|
+
|
50
|
+
after do
|
51
|
+
Delayed::Worker.exit_on_complete = false
|
52
|
+
end
|
53
|
+
|
54
|
+
it "exits the loop when no jobs are available" do
|
55
|
+
worker = Delayed::Worker.new
|
56
|
+
Timeout::timeout(2) do
|
57
|
+
worker.start
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
40
61
|
end
|
metadata
CHANGED
@@ -1,137 +1,61 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delayed_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.4
|
5
4
|
prerelease:
|
5
|
+
version: 3.0.5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Brandon Keepers
|
9
9
|
- Brian Ryckbost
|
10
|
-
- Steve Richert
|
11
10
|
- Chris Gaffney
|
12
|
-
- Brandon Keepers
|
13
|
-
- Tobias Lütke
|
14
11
|
- David Genord II
|
12
|
+
- Erik Michaels-Ober
|
13
|
+
- Matt Griffin
|
14
|
+
- Steve Richert
|
15
|
+
- Tobias Lütke
|
15
16
|
autorequire:
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
|
-
date:
|
19
|
+
date: 2013-01-28 00:00:00.000000000 Z
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
name: activesupport
|
22
|
-
requirement: !ruby/object:Gem::Requirement
|
23
|
-
none: false
|
24
|
-
requirements:
|
25
|
-
- - ~>
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '3.0'
|
28
22
|
type: :runtime
|
29
|
-
prerelease: false
|
30
23
|
version_requirements: !ruby/object:Gem::Requirement
|
31
24
|
none: false
|
32
25
|
requirements:
|
33
26
|
- - ~>
|
34
27
|
- !ruby/object:Gem::Version
|
35
28
|
version: '3.0'
|
36
|
-
|
37
|
-
name: activerecord
|
38
|
-
requirement: !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
|
-
requirements:
|
41
|
-
- - ~>
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: '3.0'
|
44
|
-
type: :development
|
29
|
+
name: activesupport
|
45
30
|
prerelease: false
|
46
|
-
version_requirements: !ruby/object:Gem::Requirement
|
47
|
-
none: false
|
48
|
-
requirements:
|
49
|
-
- - ~>
|
50
|
-
- !ruby/object:Gem::Version
|
51
|
-
version: '3.0'
|
52
|
-
- !ruby/object:Gem::Dependency
|
53
|
-
name: actionmailer
|
54
31
|
requirement: !ruby/object:Gem::Requirement
|
55
32
|
none: false
|
56
33
|
requirements:
|
57
34
|
- - ~>
|
58
35
|
- !ruby/object:Gem::Version
|
59
36
|
version: '3.0'
|
60
|
-
|
61
|
-
prerelease: false
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
none: false
|
64
|
-
requirements:
|
65
|
-
- - ~>
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '3.0'
|
68
|
-
- !ruby/object:Gem::Dependency
|
69
|
-
name: rspec
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
-
none: false
|
72
|
-
requirements:
|
73
|
-
- - ~>
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '2.0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
none: false
|
80
|
-
requirements:
|
81
|
-
- - ~>
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: '2.0'
|
84
|
-
- !ruby/object:Gem::Dependency
|
85
|
-
name: rake
|
86
|
-
requirement: !ruby/object:Gem::Requirement
|
87
|
-
none: false
|
88
|
-
requirements:
|
89
|
-
- - ! '>='
|
90
|
-
- !ruby/object:Gem::Version
|
91
|
-
version: '0'
|
92
|
-
type: :development
|
93
|
-
prerelease: false
|
94
|
-
version_requirements: !ruby/object:Gem::Requirement
|
95
|
-
none: false
|
96
|
-
requirements:
|
97
|
-
- - ! '>='
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
version: '0'
|
100
|
-
- !ruby/object:Gem::Dependency
|
101
|
-
name: simplecov
|
102
|
-
requirement: !ruby/object:Gem::Requirement
|
103
|
-
none: false
|
104
|
-
requirements:
|
105
|
-
- - ! '>='
|
106
|
-
- !ruby/object:Gem::Version
|
107
|
-
version: '0'
|
108
|
-
type: :development
|
109
|
-
prerelease: false
|
110
|
-
version_requirements: !ruby/object:Gem::Requirement
|
111
|
-
none: false
|
112
|
-
requirements:
|
113
|
-
- - ! '>='
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version: '0'
|
116
|
-
description: ! 'Delayed_job (or DJ) encapsulates the common pattern of asynchronously
|
37
|
+
description: Delayed_job (or DJ) encapsulates the common pattern of asynchronously
|
117
38
|
executing longer tasks in the background. It is a direct extraction from Shopify
|
118
39
|
where the job table is responsible for a multitude of core tasks.
|
119
|
-
|
120
|
-
|
121
|
-
This gem is collectiveidea''s fork (http://github.com/collectiveidea/delayed_job).'
|
122
40
|
email:
|
123
41
|
- brian@collectiveidea.com
|
124
42
|
executables: []
|
125
43
|
extensions: []
|
126
|
-
extra_rdoc_files:
|
127
|
-
- README.textile
|
44
|
+
extra_rdoc_files: []
|
128
45
|
files:
|
46
|
+
- CHANGELOG.md
|
47
|
+
- CONTRIBUTING.md
|
48
|
+
- LICENSE.md
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- delayed_job.gemspec
|
129
52
|
- contrib/delayed_job.monitrc
|
130
53
|
- contrib/delayed_job_multiple.monitrc
|
131
54
|
- lib/delayed/backend/base.rb
|
132
55
|
- lib/delayed/backend/shared_spec.rb
|
133
56
|
- lib/delayed/command.rb
|
134
57
|
- lib/delayed/deserialization_error.rb
|
58
|
+
- lib/delayed/exceptions.rb
|
135
59
|
- lib/delayed/lifecycle.rb
|
136
60
|
- lib/delayed/message_sending.rb
|
137
61
|
- lib/delayed/performable_mailer.rb
|
@@ -165,16 +89,11 @@ files:
|
|
165
89
|
- spec/test_backend_spec.rb
|
166
90
|
- spec/worker_spec.rb
|
167
91
|
- spec/yaml_ext_spec.rb
|
168
|
-
- MIT-LICENSE
|
169
|
-
- README.textile
|
170
92
|
homepage: http://github.com/collectiveidea/delayed_job
|
171
|
-
licenses:
|
93
|
+
licenses:
|
94
|
+
- MIT
|
172
95
|
post_install_message:
|
173
|
-
rdoc_options:
|
174
|
-
- --main
|
175
|
-
- README.textile
|
176
|
-
- --inline-source
|
177
|
-
- --line-numbers
|
96
|
+
rdoc_options: []
|
178
97
|
require_paths:
|
179
98
|
- lib
|
180
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -182,19 +101,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
182
101
|
requirements:
|
183
102
|
- - ! '>='
|
184
103
|
- !ruby/object:Gem::Version
|
185
|
-
version: '0'
|
186
104
|
segments:
|
187
105
|
- 0
|
188
|
-
hash:
|
106
|
+
hash: -2181840438794321912
|
107
|
+
version: '0'
|
189
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
190
109
|
none: false
|
191
110
|
requirements:
|
192
111
|
- - ! '>='
|
193
112
|
- !ruby/object:Gem::Version
|
194
|
-
version: '0'
|
195
113
|
segments:
|
196
114
|
- 0
|
197
|
-
hash:
|
115
|
+
hash: -2181840438794321912
|
116
|
+
version: '0'
|
198
117
|
requirements: []
|
199
118
|
rubyforge_project:
|
200
119
|
rubygems_version: 1.8.23
|