queue_dispatcher 2.3.0 → 2.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/lib/queue_dispatcher/acts_as_task.rb +39 -2
- data/lib/queue_dispatcher/acts_as_task_queue.rb +25 -11
- data/lib/queue_dispatcher/version.rb +1 -1
- data/queue_dispatcher.gemspec +9 -8
- data/script/queue_worker_dispatcher +21 -4
- metadata +22 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b13a171b35ddf613aa446a4c918a1e994ec24e3
|
4
|
+
data.tar.gz: 0e831f41b6d5815e4418946cb7b6a924444a360b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 877e9ea6a9313f4b73c3d15f0cfdcfa07d7b6524f7b84df26b9765a986af0124852bdfcbe321301a4dc2dd8bd5ee1234bf314d8ac71111c8dac482ec49066615
|
7
|
+
data.tar.gz: 9319b0f7053f7a1e712d6e458ad12cbc55830a93edbe1442dabf5ea6224cdaadbb05ca7155796d20296b08de9b79b5fb853afef59b4f003379774273daa340d4
|
data/CHANGELOG.md
ADDED
@@ -40,6 +40,15 @@ module QueueDispatcher
|
|
40
40
|
belongs_to :dependent_task, :class_name => '#{self.name}'
|
41
41
|
}
|
42
42
|
end
|
43
|
+
|
44
|
+
|
45
|
+
[:success, :error].each do |state|
|
46
|
+
define_method("on_#{state}") do |*method_names|
|
47
|
+
method_names.each do |method_name|
|
48
|
+
eval "(@#{state}_callback_chain ||= []) << method_name"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
43
52
|
end
|
44
53
|
|
45
54
|
|
@@ -47,6 +56,13 @@ module QueueDispatcher
|
|
47
56
|
def acts_as_task_config
|
48
57
|
@acts_as_task_config
|
49
58
|
end
|
59
|
+
|
60
|
+
|
61
|
+
[:success, :error].each do |state|
|
62
|
+
define_method("#{state}_callback_chain") do
|
63
|
+
eval("@#{state}_callback_chain") || []
|
64
|
+
end
|
65
|
+
end
|
50
66
|
end
|
51
67
|
|
52
68
|
|
@@ -74,7 +90,7 @@ module QueueDispatcher
|
|
74
90
|
|
75
91
|
|
76
92
|
# This method updates the task state according to the return code of their corresponding command and removes it from the task_queue
|
77
|
-
def
|
93
|
+
def update_state_and_exec_callbacks(result, remove_from_queue = false, logger = nil)
|
78
94
|
rc = output = error_msg = nil
|
79
95
|
|
80
96
|
if result.methods.map(&:to_sym).include?(:rc) && result.methods.map(&:to_sym).include?(:output) && result.methods.map(&:to_sym).include?(:error_msg)
|
@@ -90,21 +106,25 @@ module QueueDispatcher
|
|
90
106
|
end
|
91
107
|
|
92
108
|
output ||= ''
|
109
|
+
successful = result.methods.map(&:to_sym).include?(:successful?) ? result.successful? : rc.nil? || rc == 0
|
93
110
|
|
94
|
-
if
|
111
|
+
if successful
|
95
112
|
self.update_attributes :state => 'successful',
|
96
113
|
:perc_finished => 100,
|
97
114
|
:message => output.truncate(10256),
|
98
115
|
:result => result
|
116
|
+
success_callbacks(logger)
|
99
117
|
else
|
100
118
|
self.update_attributes :state => 'error',
|
101
119
|
:error_msg => error_msg,
|
102
120
|
:message => output.truncate(10256),
|
103
121
|
:result => result
|
122
|
+
error_callbacks(logger)
|
104
123
|
end
|
105
124
|
|
106
125
|
self.update_attributes :task_queue_id => nil if remove_from_queue
|
107
126
|
|
127
|
+
|
108
128
|
rc
|
109
129
|
end
|
110
130
|
|
@@ -216,6 +236,23 @@ module QueueDispatcher
|
|
216
236
|
payload.send(method_name, *args)
|
217
237
|
end
|
218
238
|
|
239
|
+
private
|
240
|
+
|
241
|
+
# Callbacks
|
242
|
+
[:success, :error].each do |state|
|
243
|
+
define_method("#{state}_callbacks") do |logger|
|
244
|
+
eval("self.class.#{state}_callback_chain").each do |method_name|
|
245
|
+
begin
|
246
|
+
send method_name
|
247
|
+
rescue => exception
|
248
|
+
backtrace = exception.backtrace.join("\n ")
|
249
|
+
msg = "Fatal error in method '#{method_name}', while executing it in #{state}_callbacks: #{$!}\n #{backtrace}"
|
250
|
+
logger.send(:error, msg) if logger
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
219
256
|
end
|
220
257
|
end
|
221
258
|
end
|
@@ -52,6 +52,26 @@ module QueueDispatcher
|
|
52
52
|
end
|
53
53
|
|
54
54
|
|
55
|
+
# Check if a certain PID is still running and is a ruby process
|
56
|
+
def pid_running?(pid)
|
57
|
+
ps = pid ? Sys::ProcTable.ps(pid) : nil
|
58
|
+
if ps
|
59
|
+
# Asume, that if the command of the 'ps'-output is 'ruby', the process is still running
|
60
|
+
ps.comm == 'ruby'
|
61
|
+
else
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
# Check if QueueDispatcher is running.
|
68
|
+
def qd_running?
|
69
|
+
running = false
|
70
|
+
TaskQueue.where(state: 'heartbeat').each { |tq| running = true if tq.updated_at > 1.minute.ago }
|
71
|
+
running
|
72
|
+
end
|
73
|
+
|
74
|
+
|
55
75
|
# Are there any running task_queues?
|
56
76
|
def any_running?
|
57
77
|
running = false
|
@@ -66,7 +86,7 @@ module QueueDispatcher
|
|
66
86
|
|
67
87
|
transaction do
|
68
88
|
# Find next task_queue which is not running and not in state error
|
69
|
-
order(:id).lock(true).all.each { |tq| task_queue = tq unless task_queue || tq.pid_running? || tq.state == 'error' }
|
89
|
+
order(:id).lock(true).all.each { |tq| task_queue = tq unless task_queue || tq.pid_running? || tq.state == 'error' || tq.state == 'heartbeat' }
|
70
90
|
|
71
91
|
# Update pid inside the atomic transaction to be sure, the next call of this method will not give the same queue a second time
|
72
92
|
task_queue.update_attribute :pid, $$ if task_queue
|
@@ -179,13 +199,7 @@ module QueueDispatcher
|
|
179
199
|
|
180
200
|
# Return true, if the command of the process with pid 'self.pid' is 'ruby'
|
181
201
|
def pid_running?
|
182
|
-
|
183
|
-
if ps
|
184
|
-
# Asume, that if the command of the 'ps'-output is 'ruby', the process is still running
|
185
|
-
ps.comm == 'ruby'
|
186
|
-
else
|
187
|
-
false
|
188
|
-
end
|
202
|
+
self.class.pid_running?(self.pid)
|
189
203
|
end
|
190
204
|
|
191
205
|
|
@@ -276,7 +290,7 @@ module QueueDispatcher
|
|
276
290
|
task_queue.update_attribute :state, 'running'
|
277
291
|
|
278
292
|
# Set logger in engine
|
279
|
-
@engine.logger = @logger if defined?
|
293
|
+
@engine.logger = @logger if defined?(@engine) && @engine.methods.include?(:logger=)
|
280
294
|
log :msg => "#{name}: Starting TaskQueue #{task_queue.id}...", :print_log => print_log
|
281
295
|
|
282
296
|
# Init. Pop first task from queue, to show init_queue-state
|
@@ -328,7 +342,7 @@ module QueueDispatcher
|
|
328
342
|
end
|
329
343
|
|
330
344
|
# Change task state according to the return code and remove it from the queue
|
331
|
-
task.
|
345
|
+
task.update_state_and_exec_callbacks(result, false, logger)
|
332
346
|
cleanup_locks_after_error_for task
|
333
347
|
task.update_attribute :task_queue_id, nil unless acts_as_task_queue_config.leave_finished_tasks_in_queue
|
334
348
|
log :msg => "#{name}: Task #{task.id} (#{task.payload.class.name}.#{task.method_name}) finished with state '#{task.state}'.", :print_log => print_log
|
@@ -378,7 +392,7 @@ module QueueDispatcher
|
|
378
392
|
backtrace = exception.backtrace.join("\n ")
|
379
393
|
log :msg => "Fatal error in method 'run!': #{$!}\n #{backtrace}", :sev => :error, :print_log => print_log
|
380
394
|
puts "Fatal error in method 'run!': #{$!}\n#{backtrace}"
|
381
|
-
task.
|
395
|
+
task.update_state_and_exec_callbacks(QueueDispatcher::RcAndMsg.bad_rc("Fatal error: #{$!}"), false, logger) if task
|
382
396
|
cleanup_locks_after_error_for task if task
|
383
397
|
task.update_attributes state: 'error' if task && task.state != 'finished'
|
384
398
|
ensure
|
data/queue_dispatcher.gemspec
CHANGED
@@ -7,17 +7,18 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = QueueDispatcher::VERSION
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Philip Kurmann"]
|
10
|
-
s.email = ["
|
11
|
-
s.
|
10
|
+
s.email = ["info@inwork.ch"]
|
11
|
+
s.license = "MIT"
|
12
|
+
s.homepage = "https://inwork.github.io/queue_dispatcher/"
|
12
13
|
s.summary = %q{This Gem installs a queue dispatcher for handling asynchronous tasks}
|
13
14
|
s.description = %q{Queue_Dispatcher executes asynchronous tasks in the background.}
|
14
15
|
|
15
|
-
s.add_dependency 'sys-proctable', '
|
16
|
-
s.add_dependency 'deadlock_retry'
|
17
|
-
s.add_dependency 'spawnling'
|
18
|
-
s.add_dependency 'haml'
|
19
|
-
s.add_dependency 'will_paginate'
|
20
|
-
s.add_dependency 'jquery-rails'
|
16
|
+
s.add_dependency 'sys-proctable', '~> 0.9'
|
17
|
+
s.add_dependency 'deadlock_retry', '~> 0'
|
18
|
+
s.add_dependency 'spawnling', '~> 0'
|
19
|
+
s.add_dependency 'haml', '~> 0'
|
20
|
+
s.add_dependency 'will_paginate', '~> 0'
|
21
|
+
s.add_dependency 'jquery-rails', '~> 0'
|
21
22
|
|
22
23
|
s.files = `git ls-files`.split("\n")
|
23
24
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -35,7 +35,8 @@ $daemon = {
|
|
35
35
|
:background => false, # background mode
|
36
36
|
:work => true, # daemon work flag
|
37
37
|
:logger_msg_prefix => nil, # Prefix for logging
|
38
|
-
:worker_pids => []
|
38
|
+
:worker_pids => [], # Remember PIDs
|
39
|
+
:heartbeat_task_queue_id => nil # Remember ID of the Heartbeat-TaskQueue
|
39
40
|
}
|
40
41
|
|
41
42
|
$worker = {
|
@@ -74,6 +75,7 @@ end
|
|
74
75
|
|
75
76
|
# Clean up before a daemon terminates
|
76
77
|
def daemon_clean_up
|
78
|
+
TaskQueue.where(id: $daemon[:heartbeat_task_queue_id]).destroy_all
|
77
79
|
File.delete($daemon[:pid_file])
|
78
80
|
end
|
79
81
|
|
@@ -137,14 +139,15 @@ def daemon_start
|
|
137
139
|
|
138
140
|
# Asume, that if the command of the 'ps'-output is 'ruby', the process is still running
|
139
141
|
if ps && (ps.comm == 'ruby')
|
140
|
-
daemon_log :msg =>
|
142
|
+
daemon_log :msg => 'Process already running!', :sev => :error
|
141
143
|
exit
|
142
144
|
else
|
143
145
|
File.delete($daemon[:pid_file])
|
144
146
|
end
|
145
147
|
end
|
146
148
|
|
147
|
-
|
149
|
+
# Start daemon
|
150
|
+
daemon_log :msg => 'Starting process...'
|
148
151
|
if $daemon[:background]
|
149
152
|
Spawnling.new { daemon_runner }
|
150
153
|
else
|
@@ -153,11 +156,25 @@ def daemon_start
|
|
153
156
|
end
|
154
157
|
|
155
158
|
|
159
|
+
# update heartbeat
|
160
|
+
def daemon_update_heartbeat
|
161
|
+
hb_tq = TaskQueue.find_by(id: $daemon[:heartbeat_task_queue_id])
|
162
|
+
if hb_tq
|
163
|
+
hb_tq.touch
|
164
|
+
else
|
165
|
+
hb_tq = TaskQueue.create(name: 'QD_HeartBeat', state: 'heartbeat', pid: Process.pid)
|
166
|
+
$daemon[:heartbeat_task_queue_id] = hb_tq.id
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
|
156
171
|
# Start an amount of workers
|
157
172
|
def spawn_and_monitor_workers
|
158
173
|
daemon_log :msg => "Spawning #{$daemon[:worker_count]} workers..."
|
159
174
|
|
160
175
|
while $daemon[:work]
|
176
|
+
daemon_update_heartbeat
|
177
|
+
|
161
178
|
# (Re)start workers
|
162
179
|
while $daemon[:worker_pids].count < $daemon[:worker_count] do
|
163
180
|
sp = Spawnling.new(:argv => $worker[:process_prefix]) do
|
@@ -197,7 +214,7 @@ def worker_runner
|
|
197
214
|
if $worker[:task_queue]
|
198
215
|
# Set Process Name and execute tasks
|
199
216
|
$0 = "#{$worker[:process_prefix]}_#{$worker[:task_queue].id}"
|
200
|
-
$worker[:task_queue].run!(:print_log => ! $daemon[:background])
|
217
|
+
$worker[:task_queue].run!(:print_log => ! $daemon[:background], logger: @logger)
|
201
218
|
else
|
202
219
|
# Set Process Name and sleep
|
203
220
|
$0 = "#{$worker[:process_prefix]}_idle"
|
metadata
CHANGED
@@ -1,107 +1,108 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queue_dispatcher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.3
|
4
|
+
version: 2.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philip Kurmann
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sys-proctable
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.9
|
19
|
+
version: '0.9'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.9
|
26
|
+
version: '0.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: deadlock_retry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: spawnling
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: haml
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: will_paginate
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: jquery-rails
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description: Queue_Dispatcher executes asynchronous tasks in the background.
|
98
98
|
email:
|
99
|
-
-
|
99
|
+
- info@inwork.ch
|
100
100
|
executables: []
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- ".gitignore"
|
105
|
+
- CHANGELOG.md
|
105
106
|
- Gemfile
|
106
107
|
- LICENSE
|
107
108
|
- README.rdoc
|
@@ -151,8 +152,9 @@ files:
|
|
151
152
|
- lib/tasks/queue_dispatcher.rake
|
152
153
|
- queue_dispatcher.gemspec
|
153
154
|
- script/queue_worker_dispatcher
|
154
|
-
homepage:
|
155
|
-
licenses:
|
155
|
+
homepage: https://inwork.github.io/queue_dispatcher/
|
156
|
+
licenses:
|
157
|
+
- MIT
|
156
158
|
metadata: {}
|
157
159
|
post_install_message:
|
158
160
|
rdoc_options: []
|
@@ -170,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
172
|
version: '0'
|
171
173
|
requirements: []
|
172
174
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
175
|
+
rubygems_version: 2.4.5
|
174
176
|
signing_key:
|
175
177
|
specification_version: 4
|
176
178
|
summary: This Gem installs a queue dispatcher for handling asynchronous tasks
|