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 +4 -4
- data/Gemfile +1 -1
- data/README.md +40 -17
- data/VERSION +1 -1
- data/bin/console +1 -1
- data/bin/unique-file +55 -0
- data/lib/sp-job.rb +9 -8
- data/lib/sp/job/back_burner.rb +301 -42
- data/lib/sp/job/broker.rb +59 -21
- data/lib/sp/job/common.rb +288 -156
- data/lib/sp/job/job_db_adapter.rb +63 -0
- data/lib/sp/job/{engine.rb → jwt.rb} +14 -12
- data/lib/sp/job/mail_queue.rb +60 -0
- data/lib/sp/job/pg_connection.rb +68 -76
- data/lib/sp/job/unique_file.rb +73 -0
- data/lib/sp/job/uploaded_image_converter.rb +35 -16
- data/lib/sp/job/worker.rb +1 -8
- data/lib/sp/job/worker_thread.rb +57 -0
- data/lib/tasks/configure.rake +66 -16
- data/sp-job.gemspec +10 -8
- metadata +23 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 759aab586beb6fd8f184cd2649a53973fbc789f5
|
4
|
+
data.tar.gz: 1827e99f054c36f10130ab89958601ea59f19627
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6311403a456ac54698ee3ecca61e7d9f192191b445bc338ce5e0496f6a7189ef8b7d11bbcf363c86d5f8f3f0bb3e4327663c17d0c6d879f1c96c08241b42a59f
|
7
|
+
data.tar.gz: 198cb7fd83ea854ed76c5b8195c0af534923d2ef46a4eedd275b7736f0b1740b041c3e5eda45b0be7df19dd7e2064a3ea3ba76e5d61ced7ee32991248710a0c6
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,36 +1,59 @@
|
|
1
1
|
# Sp::Job
|
2
2
|
|
3
|
-
|
3
|
+
# Execute the job
|
4
4
|
|
5
|
-
|
5
|
+
The job is executed method perform of the job class. If the tube is called 'park-fun'
|
6
6
|
|
7
|
-
|
7
|
+
```ruby
|
8
|
+
class ParkFun
|
8
9
|
|
9
|
-
|
10
|
+
def self.perform (job)
|
11
|
+
|
12
|
+
end
|
10
13
|
|
11
|
-
```ruby
|
12
|
-
gem 'sp-job'
|
13
14
|
```
|
14
15
|
|
15
|
-
|
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
|
-
|
40
|
+
Returns an xxx
|
18
41
|
|
19
|
-
|
42
|
+
## db.query
|
20
43
|
|
21
|
-
|
44
|
+
# Redis
|
22
45
|
|
23
|
-
|
46
|
+
Use the redis accessor to obtain a Redis object already connected
|
24
47
|
|
25
|
-
|
48
|
+
# Sending mails
|
26
49
|
|
27
|
-
|
50
|
+
Call send_mail
|
28
51
|
|
29
|
-
|
52
|
+
# Job configuration
|
30
53
|
|
31
|
-
|
54
|
+
Use config
|
32
55
|
|
33
|
-
|
56
|
+
# Logging
|
34
57
|
|
35
|
-
|
58
|
+
Use logger
|
36
59
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.2
|
data/bin/console
CHANGED
data/bin/unique-file
ADDED
@@ -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
|
data/lib/sp-job.rb
CHANGED
@@ -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 '
|
32
|
-
require 'oauth2'
|
33
|
-
require '
|
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/
|
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'
|
data/lib/sp/job/back_burner.rb
CHANGED
@@ -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
|
28
|
-
$rollbar
|
29
|
-
$
|
30
|
-
$
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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[:
|
45
|
-
opts.on('-l', '--log=LOGFILE' , "path to log file (default: '#{$args[:log_file]}')")
|
46
|
-
opts.on('-d', '--debug' , "developer mode: log to stdout and print job")
|
47
|
-
opts.on('-v', '--log_level=LEVEL' , "Log level DEBUG, INFO, WARN, ERROR, FATAL")
|
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
|
73
|
-
config.on_error
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
-
|
79
|
-
|
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
|
-
|
84
|
-
|
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
|
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
|
-
|
152
|
-
|
153
|
-
|
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
|
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
|
197
|
-
$
|
198
|
-
$
|
199
|
-
$
|
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:
|
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
|
+
}
|