sp-job 0.1.17 → 0.2.2

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: dace51fb1d47771f51c07c8245a5190ef8a24ebb
4
- data.tar.gz: 63e157d0906ae4678e0d0495864726d44f9b67ce
3
+ metadata.gz: 759aab586beb6fd8f184cd2649a53973fbc789f5
4
+ data.tar.gz: 1827e99f054c36f10130ab89958601ea59f19627
5
5
  SHA512:
6
- metadata.gz: d8e740ec15d49f33aa7853fe45871c4bcae2b954c1a6655f7c781cb092f229dd77931f2cc7aa7bc34b76bc31317cc387d5a66d5458ae718869e17e150cbac250
7
- data.tar.gz: a35ae11692e8d538533b7074dbb1521c03ee512e26e065dba80b2bba93c1c8af3c392e71140c4011a07ccb7d25ff966874f5e69bae69b9f004c3f83f034869a6
6
+ metadata.gz: 6311403a456ac54698ee3ecca61e7d9f192191b445bc338ce5e0496f6a7189ef8b7d11bbcf363c86d5f8f3f0bb3e4327663c17d0c6d879f1c96c08241b42a59f
7
+ data.tar.gz: 198cb7fd83ea854ed76c5b8195c0af534923d2ef46a4eedd275b7736f0b1740b041c3e5eda45b0be7df19dd7e2064a3ea3ba76e5d61ced7ee32991248710a0c6
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in sp-job.gemspec
4
4
  gemspec
5
5
 
6
- gem 'sp-duh', git: 'git@github.com:vpfpinho/sp-duh.git'
6
+ #gem 'sp-duh', git: 'git@github.com:vpfpinho/sp-duh.git'
data/README.md CHANGED
@@ -1,36 +1,59 @@
1
1
  # Sp::Job
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sp/job`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ # Execute the job
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ The job is executed method perform of the job class. If the tube is called 'park-fun'
6
6
 
7
- ## Installation
7
+ ```ruby
8
+ class ParkFun
8
9
 
9
- Add this line to your application's Gemfile:
10
+ def self.perform (job)
11
+
12
+ end
10
13
 
11
- ```ruby
12
- gem 'sp-job'
13
14
  ```
14
15
 
15
- And then execute:
16
+ ## Return the job result
17
+
18
+ use send_response(result: object)
19
+
20
+ ## Report a non-fatal error
21
+
22
+ return report_error(message: 'i18n_message_key", args)
23
+
24
+ ## Report a fatal error
25
+
26
+ Use raise_error(message: 'i18n_message_key", args)
27
+
28
+ # Database access
29
+
30
+ Use the `db` object.
31
+
32
+ ## db.exec
33
+
34
+ The first argument is the query string followed by a variable number of arguments that are bound to the query.
35
+
36
+ ```ruby
37
+ db.exec('SELECT fun FROM public.park where id=$1', id_value)
38
+ ```
16
39
 
17
- $ bundle
40
+ Returns an xxx
18
41
 
19
- Or install it yourself as:
42
+ ## db.query
20
43
 
21
- $ gem install sp-job
44
+ # Redis
22
45
 
23
- ## Usage
46
+ Use the redis accessor to obtain a Redis object already connected
24
47
 
25
- TODO: Write usage instructions here
48
+ # Sending mails
26
49
 
27
- ## Development
50
+ Call send_mail
28
51
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
52
+ # Job configuration
30
53
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+ Use config
32
55
 
33
- ## Contributing
56
+ # Logging
34
57
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sp-job.
58
+ Use logger
36
59
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.17
1
+ 0.2.2
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
- require "sp/job"
4
+ require "sp-job"
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2011-2018 Cloudware S.A. All rights reserved.
4
+ #
5
+ # This file is part of sp-job.
6
+ #
7
+ # sp-job is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Affero General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # sp-job is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Affero General Public License
18
+ # along with sp-job. If not, see <http://www.gnu.org/licenses/>.
19
+ #
20
+ # encoding: utf-8
21
+ #
22
+
23
+
24
+ require 'ap'
25
+ require 'bundler/setup'
26
+ require 'optparse'
27
+ require 'sp/job/unique_file'
28
+ require 'syslog/logger'
29
+
30
+ begin
31
+
32
+ $args = {}
33
+ $config = {}
34
+
35
+ #
36
+ # Parse command line arguments
37
+ #
38
+ $option_parser = OptionParser.new do |opts|
39
+ opts.banner = "Usage: #{$PROGRAM_NAME} ARGS"
40
+ opts.on('-p', '--path=PATH', 'Path to where file will be created') { |v| $args[:path] = v }
41
+ opts.on('-e', '--extension=EXTENSION', 'File extension') { |v| $args[:ext] = v }
42
+ end
43
+ $option_parser.parse!
44
+
45
+ raise 'Must specify path' if $args[:path].nil?
46
+ raise 'Must specify extension' if $args[:ext].nil?
47
+
48
+ raise 'Path not writable' unless File.writable?($args[:path])
49
+
50
+ file = SP::Job::Unique::File.create($args[:path], ".#{$args[:ext]}")
51
+
52
+ raise 'Could not create file'.red if file.nil?
53
+
54
+ puts file
55
+ end
@@ -24,22 +24,23 @@ require 'redis'
24
24
  require 'backburner'
25
25
  require 'json'
26
26
  require 'fileutils'
27
- require 'concurrent'
28
27
  require 'optparse'
29
28
  require 'os'
30
29
  require 'pg'
31
- require 'sp-duh'
32
- require 'oauth2'
33
- require 'oauth2-client'
34
- require 'curb'
35
- require 'rails'
30
+ require 'oauth2' unless RUBY_ENGINE == 'jruby'
31
+ require 'oauth2-client' unless RUBY_ENGINE == 'jruby'
32
+ require 'curb' unless RUBY_ENGINE == 'jruby'
36
33
  require 'erb'
37
34
  require 'ostruct'
38
35
  require 'json'
39
36
  require 'mail'
37
+ require 'uri'
40
38
 
41
39
  require 'sp/job'
42
- require 'sp/job/engine'
43
40
  require 'sp/job/version'
44
41
  require 'sp/job/worker'
45
- require 'sp/job/broker_oauth2_client'
42
+ require 'sp/job/worker_thread'
43
+ require 'sp/job/common'
44
+ require 'sp/job/unique_file'
45
+ require 'sp/job/broker_http_client' unless RUBY_ENGINE == 'jruby'
46
+ require 'sp/job/broker_oauth2_client' unless RUBY_ENGINE == 'jruby'
@@ -19,21 +19,75 @@
19
19
  # encoding: utf-8
20
20
  #
21
21
  require 'sp/job/pg_connection'
22
+ require 'sp/job/job_db_adapter'
22
23
  require 'roadie'
24
+ require 'thread'
25
+
26
+ module SP
27
+ module Job
28
+
29
+ class JobCancelled < ::StandardError
30
+
31
+ end
32
+
33
+ class JobAborted < ::StandardError
34
+ end
35
+
36
+ class JobException < ::StandardError
37
+
38
+ attr_reader :job
39
+ attr_reader :args
40
+
41
+ def initialize (args:, job: nil)
42
+ super(args[:message] || $current_job[:tube] || $args[:program_name])
43
+ @job = job
44
+ @args = args
45
+ end
46
+
47
+ end
48
+
49
+ class Logger < ::Logger
50
+
51
+ def task (sequence, text, success = true)
52
+ if success
53
+ info "[#{sequence}] #{text} \xE2\x9C\x94".green
54
+ else
55
+ info "[#{sequence}] #{text} \xE2\x9D\x8C".red
56
+ end
57
+ end
58
+ end
59
+
60
+ class ThreadData < Struct.new(:job_status, :report_time_stamp, :exception_reported, :job_id, :publish_key, :job_key, :current_job, :job_notification, :jsonapi)
61
+ def initialize
62
+ @job_status = {}
63
+ if $config[:options] && $config[:options][:jsonapi] == true
64
+ @jsonapi = SP::Duh::JSONAPI::Service.new($pg, nil, SP::Job::JobDbAdapter)
65
+ end
66
+ end
67
+ end
68
+
69
+ class FauxMutex
70
+ def synchronize (&block)
71
+ yield
72
+ end
73
+ end
74
+
75
+ end
76
+ end
77
+
23
78
 
24
79
  #
25
80
  # Initialize global data needed for configuration
26
81
  #
27
- $prefix = OS.mac? ? '/usr/local' : '/'
28
- $rollbar = false
29
- $bury = false
30
- $min_progress = 3 # TODO to config??
31
- $args = {
32
- stdout: false,
33
- log_level: 'info',
34
- program_name: File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME)),
35
- config_file: File.join($prefix, 'etc', File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME)), 'conf.json'),
36
- log_file: File.join($prefix, 'var', 'log', 'jobs', "#{File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))}.log")
82
+ $prefix = OS.mac? ? '/usr/local' : ''
83
+ $rollbar = false
84
+ $min_progress = 3
85
+ $args = {
86
+ stdout: false,
87
+ log_level: 'info',
88
+ program_name: File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME)),
89
+ config_file: File.join($prefix, 'etc', File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME)), 'conf.json'),
90
+ default_log_file: File.join($prefix, 'var', 'log', 'jobs', "#{File.basename($PROGRAM_NAME, File.extname($PROGRAM_NAME))}.log")
37
91
  }
38
92
 
39
93
  #
@@ -41,17 +95,62 @@ $args = {
41
95
  #
42
96
  $option_parser = OptionParser.new do |opts|
43
97
  opts.banner = "Usage: #{$PROGRAM_NAME} ARGS"
44
- opts.on('-c', '--config=CONFIG.JSON', "path to json configuration file (default: '#{$args[:config_file]}')") { |v| $args[:config_file] = File.expand_path(v) }
45
- opts.on('-l', '--log=LOGFILE' , "path to log file (default: '#{$args[:log_file]}')") { |v| $args[:log_file] = File.expand_path(v) }
46
- opts.on('-d', '--debug' , "developer mode: log to stdout and print job") { $args[:debug] = true }
47
- opts.on('-v', '--log_level=LEVEL' , "Log level DEBUG, INFO, WARN, ERROR, FATAL") { |v| $args[:log_level] = v }
98
+ opts.on('-c', '--config=CONFIG.JSON', "path to json configuration file (default: '#{$args[:default_log_file]}')") { |v| $args[:config_file] = File.expand_path(v) }
99
+ opts.on('-l', '--log=LOGFILE' , "path to log file (default: '#{$args[:log_file]}')") { |v| $args[:log_file] = File.expand_path(v) }
100
+ opts.on('-d', '--debug' , "developer mode: log to stdout and print job") { $args[:debug] = true }
101
+ opts.on('-v', '--log_level=LEVEL' , "Log level DEBUG, INFO, WARN, ERROR, FATAL") { |v| $args[:log_level] = v }
102
+ opts.on('-i', '--index=IDX' , "systemd instance index") { |v| $args[:index] = v }
48
103
  end
49
104
  $option_parser.parse!
50
105
 
106
+ if $args[:debug]
107
+ require 'ruby-debug' if RUBY_ENGINE == 'jruby'
108
+ end
109
+
110
+ # Adjust log file if need, user specified option always takes precedence
111
+ #
112
+ if $args[:log_file].nil?
113
+ if $args[:index].nil?
114
+ $args[:log_file] = $args[:default_log_file]
115
+ else
116
+ $args[:log_file] = File.join($prefix, 'var', 'log', 'jobs', "#{$args[:program_name]}.#{$args[:index]}.log")
117
+ end
118
+ end
119
+
120
+ #
121
+ # Create PID file for this jobs instance
122
+ #
123
+ if OS.mac?
124
+ Dir.mkdir("#{$prefix}/var/run/jobs") unless Dir.exist? "#{$prefix}/var/run/jobs"
125
+ end
126
+ File.write("#{$prefix}/var/run/jobs/#{$args[:program_name]}#{$args[:index].nil? ? '' : '.' + $args[:index]}.pid", Process.pid)
127
+
51
128
  #
52
129
  # Read configuration
53
130
  #
54
131
  $config = JSON.parse(File.read(File.expand_path($args[:config_file])), symbolize_names: true)
132
+ $min_progress = $config[:options][:min_progress]
133
+
134
+ #
135
+ # Global data for mutex and sync
136
+ #
137
+ $threads = [ Thread.current ]
138
+ $thread_data = {}
139
+ $thread_data[Thread.current] = ::SP::Job::ThreadData.new
140
+
141
+ #
142
+ # Sanity check we only support multithreading on JRUBY
143
+ #
144
+ if $config[:options] && $config[:options][:threads].to_i > 1
145
+ raise 'Multithreading is not supported in MRI/CRuby' unless RUBY_ENGINE == 'jruby'
146
+ $redis_mutex = Mutex.new
147
+ $roolbar_mutex = Mutex.new
148
+ $multithreading = true
149
+ else
150
+ $redis_mutex = nil
151
+ $roolbar_mutex = ::SP::Job::FauxMutex.new
152
+ $multithreading = false
153
+ end
55
154
 
56
155
  #
57
156
  # Configure rollbar
@@ -69,25 +168,50 @@ end
69
168
  #
70
169
  Backburner.configure do |config|
71
170
 
72
- config.beanstalk_url = "beanstalk://#{$config[:beanstalkd][:host]}:#{$config[:beanstalkd][:port]}"
73
- config.on_error = lambda { |e|
74
- if $exception_reported == false
75
- $exception_reported == true
76
- update_progress(status: 'error', message: e)
171
+ config.beanstalk_url = "beanstalk://#{$config[:beanstalkd][:host]}:#{$config[:beanstalkd][:port]}"
172
+ config.on_error = lambda { |e|
173
+ td = thread_data
174
+ if td.exception_reported == false
175
+ td.exception_reported = true
176
+ if e.instance_of? Beaneater::DeadlineSoonError
177
+ logger.warn "got a deadline warning".red
178
+ else
179
+ begin
180
+ raise_error(message: e)
181
+ rescue => e
182
+ # Do not retrow!!!!
183
+ end
184
+ end
77
185
  end
78
- if $rollbar
79
- Rollbar.error(e)
186
+
187
+ # Report exception to rollbar
188
+ $roolbar_mutex.synchronize {
189
+ if $rollbar
190
+ if e.instance_of? ::SP::Job::JobException
191
+ e.job[:password] = '<redacted>'
192
+ Rollbar.error(e, e.message, { job: e.job, args: e.args})
193
+ else
194
+ Rollbar.error(e)
195
+ end
196
+ end
197
+ }
198
+
199
+ # Catch fatal exception that must be handled with a restarts (systemctl will restart us)
200
+ case e
201
+ when PG::UnableToSend, PG::AdminShutdown, PG::ConnectionBad
202
+ logger.fatal "Lost connection to database exiting now"
203
+ exit
204
+ when Redis::CannotConnectError
205
+ logger.fatal "Can't connect to redis exiting now"
206
+ exit
80
207
  end
81
- catch_fatal_exceptions(e)
82
208
  }
83
- #config.priority_labels = { :custom => 50, :useless => 1000 }
84
- #config.max_job_retries = 0 # default 0 retries
85
- #config.retry_delay = 5 # default 5 seconds
86
- #config.default_priority = 65536
209
+ config.max_job_retries = ($config[:options] && $config[:options][:max_job_retries]) ? $config[:options][:max_job_retries] : 0
210
+ config.retry_delay = ($config[:options] && $config[:options][:retry_delay]) ? $config[:options][:retry_delay] : 5
87
211
  config.retry_delay_proc = lambda { |min_retry_delay, num_retries| min_retry_delay + (num_retries ** 3) }
88
212
  config.respond_timeout = 120
89
- config.default_worker = SP::Job::Worker
90
- config.logger = $args[:debug] ? Logger.new(STDOUT) : Logger.new($args[:log_file])
213
+ config.default_worker = $config[:options] && $config[:options][:threads].to_i > 1 ? SP::Job::WorkerThread : SP::Job::Worker
214
+ config.logger = $args[:debug] ? SP::Job::Logger.new(STDOUT) : SP::Job::Logger.new($args[:log_file])
91
215
  config.logger.formatter = proc do |severity, datetime, progname, msg|
92
216
  date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
93
217
  "[#{date_format}] #{severity}: #{msg}\n"
@@ -136,8 +260,42 @@ if $config[:mail]
136
260
  end
137
261
 
138
262
  #
139
- # Monkey patches to keep the tube name as plain vannila job name
263
+ # Monkey patches the sad reality of ruby development
140
264
  #
265
+ if RUBY_ENGINE == 'jruby'
266
+
267
+ class Logger
268
+ class LogDevice
269
+
270
+ def write(message)
271
+ begin
272
+ synchronize do
273
+ if @shift_age and @dev.respond_to?(:stat)
274
+ begin
275
+ check_shift_log
276
+ rescue
277
+ warn("log shifting failed. #{$!}")
278
+ end
279
+ end
280
+ begin
281
+ @dev.write(message)
282
+ rescue ::SP::Job::JobCancelled => jc
283
+ raise jc
284
+ rescue
285
+ warn("log writing failed. #{$!}")
286
+ end
287
+ end
288
+ rescue ::SP::Job::JobCancelled => jc
289
+ raise jc
290
+ rescue Exception => ignored
291
+ warn("log writing failed. #{ignored}")
292
+ end
293
+ end
294
+
295
+ end
296
+ end
297
+ end
298
+
141
299
  module Backburner
142
300
  module Helpers
143
301
 
@@ -148,19 +306,49 @@ module Backburner
148
306
  end
149
307
 
150
308
  module Logger
151
- def log_job_begin(name, args)
152
- log_info "Work job #{name}"
153
- @job_started_at = Time.now
309
+
310
+ if RUBY_ENGINE != 'jruby'
311
+
312
+ def log_job_begin(name, args)
313
+ log_info "Work job #{name}"
314
+ @job_started_at = Time.now
315
+ end
316
+
317
+ else
318
+
319
+ def log_job_begin(name, args)
320
+ log_info "Work job #{name}"
321
+ Thread.current[:job_started_at] = Time.now
322
+ end
323
+
324
+ # Print out when a job completed
325
+ # If message is nil, job is considered complete
326
+ def log_job_end(name, message = nil)
327
+ ellapsed = Time.now - Thread.current[:job_started_at]
328
+ ms = (ellapsed.to_f * 1000).to_i
329
+ action_word = message ? 'Finished' : 'Completed'
330
+ log_info("#{action_word} #{name} in #{ms}ms #{message}")
331
+ end
332
+
154
333
  end
155
334
  end
156
335
 
157
336
  class Job
337
+ extend SP::Job::Common # to bring in logger and report_error into this class
338
+
158
339
  # Processes a job and handles any failure, deleting the job once complete
159
340
  #
160
341
  # @example
161
342
  # @task.process
162
343
  #
163
344
  def process
345
+ # Invoke the job setup function, bailout if the setup returns false
346
+ unless job_class.respond_to?(:prepare_job) && job_class.prepare_job(*args)
347
+ task.delete
348
+ logger.warn "Delete stale or preempted task".red
349
+ return false
350
+ end
351
+
164
352
  # Invoke before hook and stop if false
165
353
  res = @hooks.invoke_hook_events(job_class, :before_perform, *args)
166
354
  unless res
@@ -179,6 +367,41 @@ module Backburner
179
367
  task.delete
180
368
  # Invoke after perform hook
181
369
  @hooks.invoke_hook_events(job_class, :after_perform, *args)
370
+ rescue ::SP::Job::JobAborted => ja
371
+ #
372
+ # This exception:
373
+ # 1. is sent to the rollbar
374
+ # 2. does not bury the job, instead the job is deleted
375
+ #
376
+ logger.debug "Received job aborted exception #{Thread.current}".yellow
377
+ unless task.nil?
378
+ logger.debug 'Task deleted'.yellow
379
+ task.delete
380
+ end
381
+ # Invoke after perform hook
382
+ @hooks.invoke_hook_events(job_class, :after_perform, *args)
383
+ thread_data.job_id = nil
384
+ rescue ::SP::Job::JobCancelled => jc
385
+ #
386
+ # This exception:
387
+ # 1. is not sent to the rollbar
388
+ # 2. does not bury the job, instead the job is deleted
389
+ #
390
+ logger.debug "Received job cancellation exception #{Thread.current}".yellow
391
+ unless task.nil?
392
+ logger.debug 'Task deleted'.yellow
393
+ task.delete
394
+ end
395
+ @hooks.invoke_hook_events(job_class, :on_failure, jc, *args)
396
+ report_error(message: 'i18n_job_cancelled', status: 'cancelled')
397
+ if $redis_mutex.nil?
398
+ $redis.hset(thread_data.job_key, 'cancelled', true)
399
+ else
400
+ $redis_mutex.synchronize {
401
+ $redis.hset(thread_data.job_key, 'cancelled', true)
402
+ }
403
+ end
404
+ thread_data.job_id = nil
182
405
  rescue => e
183
406
  @hooks.invoke_hook_events(job_class, :on_failure, e, *args)
184
407
  raise e
@@ -186,20 +409,56 @@ module Backburner
186
409
  end
187
410
  end
188
411
 
189
- # Mix-in the mix-in in the script so that we can use the Common module functions
190
- require 'sp/job/common'
412
+ # Mix-in the common mix-in to make code available for the lambdas used in this file
191
413
  extend SP::Job::Common
192
414
 
415
+ logger.debug "Log file ... #{$args[:log_file]}"
416
+ logger.debug "PID ........ #{Process.pid}"
417
+
193
418
  #
194
419
  # Now create the global data needed by the mix-in methods
195
420
  #
196
- $connected = false
197
- $job_status = {}
198
- $validity = 2
199
- $redis = Redis.new(:host => $config[:redis][:host], :port => $config[:redis][:port], :db => 0)
200
- $beaneater = Beaneater.new "#{$config[:beanstalkd][:host]}:#{$config[:beanstalkd][:port]}"
201
- $check_db_life_span = false
202
- $status_dirty = false
421
+ $connected = false
422
+ $redis = Redis.new(:host => $config[:redis][:host], :port => $config[:redis][:port], :db => 0)
423
+ $transient_job = $config[:options] && $config[:options][:transient] == true
424
+ $beaneater = Beaneater.new "#{$config[:beanstalkd][:host]}:#{$config[:beanstalkd][:port]}"
203
425
  if $config[:postgres] && $config[:postgres][:conn_str]
204
- $pg = ::SP::Job::PGConnection.new(owner: 'back_burner', config: $config[:postgres])
426
+ $pg = ::SP::Job::PGConnection.new(owner: $PROGRAM_NAME, config: $config[:postgres], multithreaded: $multithreading)
427
+ if $PROGRAM_NAME.split('/').last == 'saft-importer' || $PROGRAM_NAME.split('/').last == 'saft-destroyer'
428
+ $pg.exec("SET log_min_duration_statement TO 0;")
429
+ end
430
+ if $config[:options][:jsonapi] == true
431
+ $jsonapi = SP::Duh::JSONAPI::Service.new($pg, ($jsonapi.nil? ? nil : $jsonapi.url), SP::Job::JobDbAdapter)
432
+ end
205
433
  end
434
+
435
+ #
436
+ # Open a second thread that will listen to cancellation and other "signals"
437
+ #
438
+ $cancel_thread = Thread.new {
439
+ begin
440
+ $subscription_redis = Redis.new(:host => $config[:redis][:host], :port => $config[:redis][:port], :db => 0)
441
+ $subscription_redis.subscribe($config[:service_id] + ':job-signal') do |on|
442
+ on.message do |channel, msg|
443
+ begin
444
+ message = JSON.parse(msg, {symbolize_names: true})
445
+ $threads.each do |thread|
446
+ if $thread_data[thread].job_id != nil && message[:id].to_s == $thread_data[thread].job_id && message[:status] == 'cancelled'
447
+ logger.info "Received cancel signal for job #{$thread_data[thread].job_id}"
448
+ thread.raise(::SP::Job::JobCancelled.new)
449
+ end
450
+ end
451
+ rescue Exception => e
452
+ # ignore invalid payloads
453
+ end
454
+ end
455
+ end
456
+ rescue Redis::CannotConnectError => ccc
457
+ logger.fatal "Can't connect to redis exiting now".red
458
+ exit
459
+ rescue Exception => e
460
+ # Forward unexpected exceptions to the main thread for proper handling
461
+ logger.fatal e.to_s.red
462
+ Thread.main.raise(e)
463
+ end
464
+ }