public
Description: Database based asynchronously priority queue system -- Extracted from Shopify
Homepage: http://www.shopify.com
Clone URL: git://github.com/tobi/delayed_job.git
Search Repo:
Renamed README to README.markdown for github formatting action
Tobias Lütke (author)
Sun Mar 23 07:09:17 -0700 2008
commit  1bea0e4281bc398777dc88c26befcd998590511e
tree    7f5edadb0c1d280cc821b08ab983e7f3a9dd6bd2
parent  3e4e1acec1c19623d93fa75bdbcdf74ae89afb41
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
@@ -1,104 +1 @@
0
-Delayed::Job
0
-============
0
-
0
-Delated_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.
0
-
0
-It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks. Amongst those tasks are:
0
-
0
-* sending massive newsletters
0
-* image resizing
0
-* http downloads
0
-* updating smart collections
0
-* updating solr, our search server, after product changes
0
-* batch imports
0
-* spam checks
0
-
0
-== Changes ==
0
-
0
-1.5 Job runners can now be run in parallel. Two new database columns are needed: locked_until and locked_by. This allows us
0
- to use pessimistic locking, which enables us to run as many worker processes as we need to speed up queue processing.
0
-1.0 Initial release
0
-
0
-== Setup ==
0
-
0
-The library evolves around a delayed_jobs table which looks as follows:
0
-
0
- create_table :delayed_jobs, :force => true do |table|
0
- table.integer :priority, :default => 0
0
- table.integer :attempts, :default => 0
0
- table.text :handler
0
- table.string :last_error
0
- table.datetime :run_at
0
- table.datetime :locked_until
0
- table.string :locked_by
0
- table.timestamps
0
- end
0
-
0
-== Usage ==
0
-
0
-Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table.
0
-Job objects are serialized to yaml so that they can later be resurrected by the job runner.
0
-
0
- class NewsletterJob < Struct.new(:text, :emails)
0
- def perform
0
- emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
0
- end
0
- end
0
-
0
- Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
0
-
0
-There is also a second way to get jobs in the queue: send_later.
0
-
0
-
0
- BatchImporter.new(Shop.find(1)).send_later(:import_massive_csv, massive_csv)
0
-
0
-
0
-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
0
-which are stored as their text representation and loaded from the database fresh when the job is actually run later.
0
-
0
-
0
-== Running the tasks ==
0
-
0
-You can invoke rake jobs:work which will start working off jobs. You can cancel the rake task by CTRL-C.
0
-
0
-At Shopify we run the the tasks from a simple script/job_runner which is being invoked by runnit:
0
-
0
- #!/usr/bin/env ruby
0
- require File.dirname(__FILE__) + '/../config/environment'
0
-
0
- SLEEP = 5
0
-
0
- trap('TERM') { puts 'Exiting...'; $exit = true }
0
- trap('INT') { puts 'Exiting...'; $exit = true }
0
-
0
- puts "*** Staring job worker #{Delayed::Job.worker_name}"
0
-
0
- begin
0
-
0
- loop do
0
- result = nil
0
-
0
- realtime = Benchmark.realtime do
0
- result = Delayed::Job.work_off
0
- end
0
-
0
- count = result.sum
0
-
0
- break if $exit
0
-
0
- if count.zero?
0
- sleep(SLEEP)
0
- puts 'Waiting for more jobs...'
0
- else
0
- status = "#{count} jobs processed at %.4f j/s, %d failed ..." % [count / realtime, result.last]
0
- RAILS_DEFAULT_LOGGER.info status
0
- puts status
0
- end
0
-
0
- break if $exit
0
- end
0
-
0
- ensure
0
- Delayed::Job.clear_locks!
0
- end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
0
@@ -1 +1,104 @@
0
+Delayed::Job
0
+============
0
+
0
+Delated_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background.
0
+
0
+It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks. Amongst those tasks are:
0
+
0
+* sending massive newsletters
0
+* image resizing
0
+* http downloads
0
+* updating smart collections
0
+* updating solr, our search server, after product changes
0
+* batch imports
0
+* spam checks
0
+
0
+== Changes ==
0
+
0
+1.5 Job runners can now be run in parallel. Two new database columns are needed: locked_until and locked_by. This allows us
0
+ to use pessimistic locking, which enables us to run as many worker processes as we need to speed up queue processing.
0
+1.0 Initial release
0
+
0
+== Setup ==
0
+
0
+The library evolves around a delayed_jobs table which looks as follows:
0
+
0
+ create_table :delayed_jobs, :force => true do |table|
0
+ table.integer :priority, :default => 0
0
+ table.integer :attempts, :default => 0
0
+ table.text :handler
0
+ table.string :last_error
0
+ table.datetime :run_at
0
+ table.datetime :locked_until
0
+ table.string :locked_by
0
+ table.timestamps
0
+ end
0
+
0
+== Usage ==
0
+
0
+Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table.
0
+Job objects are serialized to yaml so that they can later be resurrected by the job runner.
0
+
0
+ class NewsletterJob < Struct.new(:text, :emails)
0
+ def perform
0
+ emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
0
+ end
0
+ end
0
+
0
+ Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).collect(&:email))
0
+
0
+There is also a second way to get jobs in the queue: send_later.
0
+
0
+
0
+ BatchImporter.new(Shop.find(1)).send_later(:import_massive_csv, massive_csv)
0
+
0
+
0
+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
0
+which are stored as their text representation and loaded from the database fresh when the job is actually run later.
0
+
0
+
0
+== Running the tasks ==
0
+
0
+You can invoke rake jobs:work which will start working off jobs. You can cancel the rake task by CTRL-C.
0
+
0
+At Shopify we run the the tasks from a simple script/job_runner which is being invoked by runnit:
0
+
0
+ #!/usr/bin/env ruby
0
+ require File.dirname(__FILE__) + '/../config/environment'
0
+
0
+ SLEEP = 5
0
+
0
+ trap('TERM') { puts 'Exiting...'; $exit = true }
0
+ trap('INT') { puts 'Exiting...'; $exit = true }
0
+
0
+ puts "*** Staring job worker #{Delayed::Job.worker_name}"
0
+
0
+ begin
0
+
0
+ loop do
0
+ result = nil
0
+
0
+ realtime = Benchmark.realtime do
0
+ result = Delayed::Job.work_off
0
+ end
0
+
0
+ count = result.sum
0
+
0
+ break if $exit
0
+
0
+ if count.zero?
0
+ sleep(SLEEP)
0
+ puts 'Waiting for more jobs...'
0
+ else
0
+ status = "#{count} jobs processed at %.4f j/s, %d failed ..." % [count / realtime, result.last]
0
+ RAILS_DEFAULT_LOGGER.info status
0
+ puts status
0
+ end
0
+
0
+ break if $exit
0
+ end
0
+
0
+ ensure
0
+ Delayed::Job.clear_locks!
0
+ end

Comments

    No one has commented yet.