queue_dispatcher 2.3.0 → 2.5.3

Sign up to get free protection for your applications and to get access to all the features.
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