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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f35bcc5afab97bb7da1c28e6c33db73216e8b29e
4
- data.tar.gz: cb909b73223caf2192d7f4a437cb2f49be17a97e
3
+ metadata.gz: 8b13a171b35ddf613aa446a4c918a1e994ec24e3
4
+ data.tar.gz: 0e831f41b6d5815e4418946cb7b6a924444a360b
5
5
  SHA512:
6
- metadata.gz: 970e6acfbb9a957ad130615294e5783c60ff2735ca3f96c756a683f8f807a1ac478351df68b8f997459e5251b43afcf5d6d6268e0b454071f0ee47a5e32041df
7
- data.tar.gz: 1eeec8fc00fa057ab6fb35856f04e0c578c0798a96832e40fcba76dd71ca65e5f08a4579e233e16fbb0a9778316874d0c262d51444ec05360780bf9f00b63c95
6
+ metadata.gz: 877e9ea6a9313f4b73c3d15f0cfdcfa07d7b6524f7b84df26b9765a986af0124852bdfcbe321301a4dc2dd8bd5ee1234bf314d8ac71111c8dac482ec49066615
7
+ data.tar.gz: 9319b0f7053f7a1e712d6e458ad12cbc55830a93edbe1442dabf5ea6224cdaadbb05ca7155796d20296b08de9b79b5fb853afef59b4f003379774273daa340d4
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 2.5.3 / 2015-08-19
2
+ ### Fixed
3
+ * Fix frozen NilClass error when no @engine instance varaiable is set
@@ -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 update_state(result, remove_from_queue = false)
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 rc.nil? || rc == 0
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
- ps = self.pid ? Sys::ProcTable.ps(self.pid) : nil
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? @engine && @engine.methods.include?(:logger=)
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.update_state result
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.update_state QueueDispatcher::RcAndMsg.bad_rc("Fatal error: #{$!}") if 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
@@ -1,3 +1,3 @@
1
1
  module QueueDispatcher
2
- VERSION = "2.3.0"
2
+ VERSION = "2.5.3"
3
3
  end
@@ -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 = ["philip.kurmann@inwork.ch"]
11
- s.homepage = ""
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', '>= 0.9.1'
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 => [] # Remember 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 => "Process already running!", :sev => :error
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
- daemon_log :msg => "Starting process..."
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.0
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-01-26 00:00:00.000000000 Z
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.1
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.1
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
- - philip.kurmann@inwork.ch
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.2.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