sp-job 0.1.17 → 0.2.2

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: 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
+ }