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