inst-jobs 2.3.1 → 2.4.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/db/migrate/20101216224513_create_delayed_jobs.rb +9 -7
  3. data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +8 -13
  4. data/db/migrate/20110610213249_optimize_delayed_jobs.rb +8 -8
  5. data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +25 -25
  6. data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +4 -8
  7. data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +1 -3
  8. data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +11 -15
  9. data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +1 -1
  10. data/db/migrate/20120608191051_add_jobs_run_at_index.rb +2 -2
  11. data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +1 -1
  12. data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +2 -3
  13. data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +9 -13
  14. data/db/migrate/20151210162949_improve_max_concurrent.rb +4 -8
  15. data/db/migrate/20161206323555_add_back_default_string_limits_jobs.rb +3 -2
  16. data/db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb +13 -17
  17. data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +8 -8
  18. data/db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb +72 -77
  19. data/db/migrate/20200825011002_add_strand_order_override.rb +93 -97
  20. data/db/migrate/20210809145804_add_n_strand_index.rb +12 -0
  21. data/db/migrate/20210812210128_add_singleton_column.rb +200 -0
  22. data/db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb +27 -0
  23. data/exe/inst_jobs +3 -2
  24. data/lib/delayed/backend/active_record.rb +204 -150
  25. data/lib/delayed/backend/base.rb +107 -77
  26. data/lib/delayed/batch.rb +11 -9
  27. data/lib/delayed/cli.rb +98 -84
  28. data/lib/delayed/core_ext/kernel.rb +4 -2
  29. data/lib/delayed/daemon.rb +70 -74
  30. data/lib/delayed/job_tracking.rb +26 -25
  31. data/lib/delayed/lifecycle.rb +27 -24
  32. data/lib/delayed/log_tailer.rb +17 -17
  33. data/lib/delayed/logging.rb +13 -16
  34. data/lib/delayed/message_sending.rb +43 -52
  35. data/lib/delayed/performable_method.rb +6 -8
  36. data/lib/delayed/periodic.rb +72 -65
  37. data/lib/delayed/plugin.rb +2 -4
  38. data/lib/delayed/pool.rb +198 -192
  39. data/lib/delayed/server/helpers.rb +6 -6
  40. data/lib/delayed/server.rb +51 -54
  41. data/lib/delayed/settings.rb +93 -81
  42. data/lib/delayed/testing.rb +21 -22
  43. data/lib/delayed/version.rb +1 -1
  44. data/lib/delayed/work_queue/in_process.rb +21 -17
  45. data/lib/delayed/work_queue/parent_process/client.rb +55 -53
  46. data/lib/delayed/work_queue/parent_process/server.rb +219 -208
  47. data/lib/delayed/work_queue/parent_process.rb +52 -53
  48. data/lib/delayed/worker/consul_health_check.rb +21 -19
  49. data/lib/delayed/worker/health_check.rb +29 -22
  50. data/lib/delayed/worker/null_health_check.rb +3 -1
  51. data/lib/delayed/worker/process_helper.rb +8 -9
  52. data/lib/delayed/worker.rb +271 -261
  53. data/lib/delayed/yaml_extensions.rb +12 -10
  54. data/lib/delayed_job.rb +37 -38
  55. data/lib/inst-jobs.rb +1 -1
  56. data/spec/active_record_job_spec.rb +129 -136
  57. data/spec/delayed/cli_spec.rb +7 -7
  58. data/spec/delayed/daemon_spec.rb +8 -8
  59. data/spec/delayed/message_sending_spec.rb +16 -9
  60. data/spec/delayed/periodic_spec.rb +13 -12
  61. data/spec/delayed/server_spec.rb +38 -38
  62. data/spec/delayed/settings_spec.rb +26 -25
  63. data/spec/delayed/work_queue/in_process_spec.rb +7 -7
  64. data/spec/delayed/work_queue/parent_process/client_spec.rb +16 -12
  65. data/spec/delayed/work_queue/parent_process/server_spec.rb +43 -40
  66. data/spec/delayed/work_queue/parent_process_spec.rb +21 -21
  67. data/spec/delayed/worker/consul_health_check_spec.rb +22 -22
  68. data/spec/delayed/worker/health_check_spec.rb +60 -52
  69. data/spec/delayed/worker_spec.rb +28 -25
  70. data/spec/sample_jobs.rb +45 -15
  71. data/spec/shared/delayed_batch.rb +74 -67
  72. data/spec/shared/delayed_method.rb +143 -102
  73. data/spec/shared/performable_method.rb +39 -38
  74. data/spec/shared/shared_backend.rb +550 -437
  75. data/spec/shared/testing.rb +14 -14
  76. data/spec/shared/worker.rb +155 -147
  77. data/spec/shared_jobs_specs.rb +13 -13
  78. data/spec/spec_helper.rb +46 -41
  79. metadata +79 -53
  80. data/lib/delayed/backend/redis/bulk_update.lua +0 -50
  81. data/lib/delayed/backend/redis/destroy_job.lua +0 -2
  82. data/lib/delayed/backend/redis/enqueue.lua +0 -29
  83. data/lib/delayed/backend/redis/fail_job.lua +0 -5
  84. data/lib/delayed/backend/redis/find_available.lua +0 -3
  85. data/lib/delayed/backend/redis/functions.rb +0 -59
  86. data/lib/delayed/backend/redis/get_and_lock_next_available.lua +0 -17
  87. data/lib/delayed/backend/redis/includes/jobs_common.lua +0 -203
  88. data/lib/delayed/backend/redis/job.rb +0 -528
  89. data/lib/delayed/backend/redis/set_running.lua +0 -5
  90. data/lib/delayed/backend/redis/tickle_strand.lua +0 -2
  91. data/spec/gemfiles/52.gemfile +0 -7
  92. data/spec/gemfiles/60.gemfile +0 -7
  93. data/spec/gemfiles/61.gemfile +0 -7
  94. data/spec/redis_job_spec.rb +0 -148
@@ -1,257 +1,267 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
-
5
- class TimeoutError < RuntimeError; end
6
- class RetriableError < RuntimeError
7
- # this error is a special case. You _should_ raise
8
- # it from inside the rescue block for another error,
9
- # because it indicates: "something made this job fail
10
- # but we're pretty sure it's transient and it's safe to try again".
11
- # the workflow is still the same (retry will happen unless
12
- # retries are exhausted), but it won't call the :error
13
- # callback unless it can't retry anymore. It WILL call the
14
- # separate ":retry" callback, which is ONLY activated
15
- # for this kind of error.
16
- end
17
-
18
- require 'tmpdir'
19
- require 'set'
20
-
21
- class Worker
22
- include Delayed::Logging
23
- SIGNALS = %i{INT TERM QUIT}
24
-
25
- attr_reader :config, :queue_name, :min_priority, :max_priority, :work_queue
26
-
27
- # Callback to fire when a delayed job fails max_attempts times. If this
28
- # callback is defined, then the value of destroy_failed_jobs is ignored, and
29
- # the job is destroyed if this block returns true.
30
- #
31
- # This allows for destroying "uninteresting" failures, while keeping around
32
- # interesting failures to be investigated later.
33
- #
34
- # The block is called with args(job, last_exception)
35
- def self.on_max_failures=(block)
36
- @@on_max_failures = block
4
+ class TimeoutError < RuntimeError; end
5
+
6
+ class RetriableError < RuntimeError
7
+ # this error is a special case. You _should_ raise
8
+ # it from inside the rescue block for another error,
9
+ # because it indicates: "something made this job fail
10
+ # but we're pretty sure it's transient and it's safe to try again".
11
+ # the workflow is still the same (retry will happen unless
12
+ # retries are exhausted), but it won't call the :error
13
+ # callback unless it can't retry anymore. It WILL call the
14
+ # separate ":retry" callback, which is ONLY activated
15
+ # for this kind of error.
37
16
  end
38
- cattr_reader :on_max_failures
39
17
 
40
- cattr_accessor :plugins
41
- self.plugins = Set.new
18
+ require "tmpdir"
19
+ require "set"
20
+
21
+ class Worker
22
+ include Delayed::Logging
23
+ SIGNALS = %i[INT TERM QUIT].freeze
24
+
25
+ attr_reader :config, :queue_name, :min_priority, :max_priority, :work_queue
26
+
27
+ class << self
28
+ # Callback to fire when a delayed job fails max_attempts times. If this
29
+ # callback is defined, then the value of destroy_failed_jobs is ignored, and
30
+ # the job is destroyed if this block returns true.
31
+ #
32
+ # This allows for destroying "uninteresting" failures, while keeping around
33
+ # interesting failures to be investigated later.
34
+ #
35
+ # The block is called with args(job, last_exception)
36
+ attr_accessor :on_max_failures
37
+ end
42
38
 
43
- def self.lifecycle
44
- @lifecycle ||= Delayed::Lifecycle.new
45
- end
39
+ cattr_accessor :plugins
40
+ self.plugins = Set.new
46
41
 
47
- def self.current_job
48
- Thread.current[:running_delayed_job]
49
- end
42
+ def self.lifecycle
43
+ @lifecycle ||= Delayed::Lifecycle.new
44
+ end
50
45
 
51
- def self.running_job(job)
52
- Thread.current[:running_delayed_job] = job
53
- yield
54
- ensure
55
- Thread.current[:running_delayed_job] = nil
56
- end
46
+ def self.current_job
47
+ Thread.current[:running_delayed_job]
48
+ end
57
49
 
58
- def initialize(options = {})
59
- @exit = false
60
- @parent_pid = options[:parent_pid]
61
- @queue_name = options[:queue] ||= Settings.queue
62
- @min_priority = options[:min_priority]
63
- @max_priority = options[:max_priority]
64
- @max_job_count = options[:worker_max_job_count].to_i
65
- @max_memory_usage = options[:worker_max_memory_usage].to_i
66
- @work_queue = options.delete(:work_queue) || WorkQueue::InProcess.new
67
- @health_check_type = Settings.worker_health_check_type
68
- @health_check_config = Settings.worker_health_check_config
69
- @config = options
70
- @job_count = 0
71
-
72
- @self_pipe = IO.pipe
73
- @signal_queue = []
74
-
75
- app = Rails.application
76
- if app && !app.config.cache_classes
77
- Delayed::Worker.lifecycle.around(:perform) do |worker, job, &block|
78
- reload = app.config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any?
79
-
80
- if reload
81
- if defined?(ActiveSupport::Reloader)
82
- Rails.application.reloader.reload!
83
- else
84
- ActionDispatch::Reloader.prepare!
50
+ def self.running_job(job)
51
+ Thread.current[:running_delayed_job] = job
52
+ yield
53
+ ensure
54
+ Thread.current[:running_delayed_job] = nil
55
+ end
56
+
57
+ def initialize(options = {})
58
+ @exit = false
59
+ @parent_pid = options[:parent_pid]
60
+ @queue_name = options[:queue] ||= Settings.queue
61
+ @min_priority = options[:min_priority]
62
+ @max_priority = options[:max_priority]
63
+ @max_job_count = options[:worker_max_job_count].to_i
64
+ @max_memory_usage = options[:worker_max_memory_usage].to_i
65
+ @work_queue = options.delete(:work_queue) || WorkQueue::InProcess.new
66
+ @health_check_type = Settings.worker_health_check_type
67
+ @health_check_config = Settings.worker_health_check_config
68
+ @config = options
69
+ @job_count = 0
70
+
71
+ @signal_queue = []
72
+
73
+ app = Rails.application
74
+ if app && !app.config.cache_classes
75
+ Delayed::Worker.lifecycle.around(:perform) do |worker, job, &block|
76
+ reload = app.config.reload_classes_only_on_change != true || app.reloaders.map(&:updated?).any?
77
+
78
+ if reload
79
+ if defined?(ActiveSupport::Reloader)
80
+ Rails.application.reloader.reload!
81
+ else
82
+ ActionDispatch::Reloader.prepare!
83
+ end
85
84
  end
86
- end
87
85
 
88
- begin
89
- block.call(worker, job)
90
- ensure
91
- ActionDispatch::Reloader.cleanup! if reload && !defined?(ActiveSupport::Reloader)
86
+ begin
87
+ block.call(worker, job)
88
+ ensure
89
+ ActionDispatch::Reloader.cleanup! if reload && !defined?(ActiveSupport::Reloader)
90
+ end
92
91
  end
93
92
  end
94
- end
95
-
96
- plugins.each { |plugin| plugin.inject! }
97
- end
98
-
99
- def name
100
- @name ||= "#{Socket.gethostname rescue "X"}:#{self.id}"
101
- end
102
93
 
103
- def set_process_name(new_name)
104
- $0 = "delayed:#{new_name}"
105
- end
94
+ plugins.each(&:inject!)
95
+ end
106
96
 
107
- def exit?
108
- !!@exit || parent_exited?
109
- end
97
+ def name
98
+ @name ||= "#{Socket.gethostname rescue 'X'}:#{id}"
99
+ end
110
100
 
111
- def parent_exited?
112
- @parent_pid && @parent_pid != Process.ppid
113
- end
101
+ def process_name=(new_name)
102
+ $0 = "delayed:#{new_name}"
103
+ end
114
104
 
115
- def wake_up
116
- @self_pipe[1].write_nonblock('.', exception: false)
117
- work_queue.wake_up
118
- end
105
+ def exit?
106
+ !!@exit || parent_exited?
107
+ end
119
108
 
120
- def start
121
- logger.info "Starting worker"
122
- set_process_name("start:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || 'max'}")
109
+ def parent_exited?
110
+ @parent_pid && @parent_pid != Process.ppid
111
+ end
123
112
 
124
- work_thread = Thread.current
125
- SIGNALS.each do |sig|
126
- trap(sig) { @signal_queue << sig; wake_up }
113
+ def wake_up
114
+ @self_pipe[1].write_nonblock(".", exception: false)
115
+ work_queue.wake_up
127
116
  end
128
117
 
129
- raise 'Could not register health_check' unless health_check.start
130
-
131
- signal_processor = Thread.new do
132
- loop do
133
- @self_pipe[0].read(1)
134
- case @signal_queue.pop
135
- when :INT, :TERM
136
- @exit = true # get the main thread to bail early if it's waiting for a job
137
- work_thread.raise(SystemExit) # Force the main thread to bail out of the current job
138
- cleanup! # we're going to get SIGKILL'd in a moment, so clean up asap
139
- break
140
- when :QUIT
141
- @exit = true
142
- else
143
- logger.error "Unknown signal '#{sig}' received"
118
+ def start
119
+ logger.info "Starting worker"
120
+ self.process_name =
121
+ "start:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || 'max'}"
122
+ @self_pipe = IO.pipe
123
+ work_queue.init
124
+
125
+ work_thread = Thread.current
126
+ SIGNALS.each do |sig|
127
+ trap(sig) do
128
+ @signal_queue << sig
129
+ wake_up
144
130
  end
145
131
  end
146
- end
147
132
 
148
- self.class.lifecycle.run_callbacks(:execute, self) do
149
- until exit? do
150
- run
133
+ raise "Could not register health_check" unless health_check.start
134
+
135
+ signal_processor = Thread.new do
136
+ loop do
137
+ @self_pipe[0].read(1)
138
+ case @signal_queue.pop
139
+ when :INT, :TERM
140
+ @exit = true # get the main thread to bail early if it's waiting for a job
141
+ work_thread.raise(SystemExit) # Force the main thread to bail out of the current job
142
+ cleanup! # we're going to get SIGKILL'd in a moment, so clean up asap
143
+ break
144
+ when :QUIT
145
+ @exit = true
146
+ else
147
+ logger.error "Unknown signal '#{sig}' received"
148
+ end
149
+ end
150
+ end
151
+
152
+ self.class.lifecycle.run_callbacks(:execute, self) do
153
+ run until exit?
151
154
  end
152
- end
153
155
 
154
- logger.info "Stopping worker"
155
- rescue => e
156
- Rails.logger.fatal("Child process died: #{e.inspect}") rescue nil
157
- self.class.lifecycle.run_callbacks(:exceptional_exit, self, e) { }
158
- ensure
159
- cleanup!
156
+ logger.info "Stopping worker"
157
+ rescue => e
158
+ Rails.logger.fatal("Child process died: #{e.inspect}") rescue nil
159
+ self.class.lifecycle.run_callbacks(:exceptional_exit, self, e) { nil }
160
+ ensure
161
+ cleanup!
160
162
 
161
- if signal_processor
162
- signal_processor.kill
163
- signal_processor.join
163
+ if signal_processor
164
+ signal_processor.kill
165
+ signal_processor.join
166
+ end
167
+
168
+ @self_pipe&.each(&:close)
169
+ @self_pipe = nil
164
170
  end
165
- end
166
171
 
167
- def cleanup!
168
- return if cleaned?
172
+ def cleanup!
173
+ return if cleaned?
169
174
 
170
- health_check.stop
171
- work_queue.close
172
- Delayed::Job.clear_locks!(name)
175
+ health_check.stop
176
+ work_queue.close
177
+ Delayed::Job.clear_locks!(name)
173
178
 
174
- @cleaned = true
175
- end
179
+ @cleaned = true
180
+ end
176
181
 
177
- def cleaned?
178
- @cleaned
179
- end
182
+ def cleaned?
183
+ @cleaned
184
+ end
180
185
 
181
- def run
182
- return if exit?
183
- self.class.lifecycle.run_callbacks(:loop, self) do
184
- set_process_name("pop:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || 'max'}")
185
- job = self.class.lifecycle.run_callbacks(:pop, self) do
186
- work_queue.get_and_lock_next_available(name, config)
187
- end
186
+ def run
187
+ return if exit?
188
188
 
189
- if job
190
- configure_for_job(job) do
191
- @job_count += perform(job)
189
+ self.class.lifecycle.run_callbacks(:loop, self) do
190
+ self.process_name =
191
+ "pop:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || 'max'}"
192
+ job = self.class.lifecycle.run_callbacks(:pop, self) do
193
+ work_queue.get_and_lock_next_available(name, config)
194
+ end
192
195
 
193
- if @max_job_count > 0 && @job_count >= @max_job_count
194
- logger.debug "Max job count of #{@max_job_count} exceeded, dying"
195
- @exit = true
196
- end
196
+ if job
197
+ configure_for_job(job) do
198
+ @job_count += perform(job)
197
199
 
198
- if @max_memory_usage > 0
199
- memory = sample_memory
200
- if memory > @max_memory_usage
201
- logger.debug "Memory usage of #{memory} exceeds max of #{@max_memory_usage}, dying"
200
+ if @max_job_count.positive? && @job_count >= @max_job_count
201
+ logger.debug "Max job count of #{@max_job_count} exceeded, dying"
202
202
  @exit = true
203
- else
204
- logger.debug "Memory usage: #{memory}"
203
+ end
204
+
205
+ if @max_memory_usage.positive?
206
+ memory = sample_memory
207
+ if memory > @max_memory_usage
208
+ logger.debug "Memory usage of #{memory} exceeds max of #{@max_memory_usage}, dying"
209
+ @exit = true
210
+ else
211
+ logger.debug "Memory usage: #{memory}"
212
+ end
205
213
  end
206
214
  end
215
+ else
216
+ self.process_name =
217
+ "wait:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || 'max'}"
218
+ sleep(Settings.sleep_delay + (rand * Settings.sleep_delay_stagger)) unless exit?
207
219
  end
208
- else
209
- set_process_name("wait:#{Settings.worker_procname_prefix}#{@queue_name}:#{min_priority || 0}:#{max_priority || 'max'}")
210
- sleep(Settings.sleep_delay + (rand * Settings.sleep_delay_stagger)) unless exit?
211
220
  end
212
221
  end
213
- end
214
222
 
215
- def perform(job)
216
- begin
217
- count = 1
218
- raise Delayed::Backend::JobExpired, "job expired at #{job.expires_at}" if job.expired?
219
- self.class.lifecycle.run_callbacks(:perform, self, job) do
220
- set_process_name("run:#{Settings.worker_procname_prefix}#{job.id}:#{job.name}")
221
- logger.info("Processing #{log_job(job, :long)}")
222
- runtime = Benchmark.realtime do
223
- if job.batch?
224
- # each job in the batch will have perform called on it, so we don't
225
- # need a timeout around this
226
- count = perform_batch(job)
227
- else
228
- job.invoke_job
223
+ def perform(job)
224
+ begin
225
+ count = 1
226
+ raise Delayed::Backend::JobExpired, "job expired at #{job.expires_at}" if job.expired?
227
+
228
+ self.class.lifecycle.run_callbacks(:perform, self, job) do
229
+ self.process_name = "run:#{Settings.worker_procname_prefix}#{job.id}:#{job.name}"
230
+ logger.info("Processing #{log_job(job, :long)}")
231
+ runtime = Benchmark.realtime do
232
+ if job.batch?
233
+ # each job in the batch will have perform called on it, so we don't
234
+ # need a timeout around this
235
+ count = perform_batch(job)
236
+ else
237
+ job.invoke_job
238
+ end
239
+ job.destroy
229
240
  end
230
- job.destroy
241
+ logger.info("Completed #{log_job(job)} #{format('%.0fms', (runtime * 1000))}")
242
+ end
243
+ rescue ::Delayed::RetriableError => e
244
+ can_retry = job.attempts + 1 < job.inferred_max_attempts
245
+ callback_type = can_retry ? :retry : :error
246
+ self.class.lifecycle.run_callbacks(callback_type, self, job, e) do
247
+ handle_failed_job(job, e)
248
+ end
249
+ rescue SystemExit => e
250
+ # There wasn't really a failure here so no callbacks and whatnot needed,
251
+ # still reschedule the job though.
252
+ job.reschedule(e)
253
+ rescue Exception => e # rubocop:disable Lint/RescueException
254
+ self.class.lifecycle.run_callbacks(:error, self, job, e) do
255
+ handle_failed_job(job, e)
231
256
  end
232
- logger.info("Completed #{log_job(job)} #{"%.0fms" % (runtime * 1000)}")
233
- end
234
- rescue ::Delayed::RetriableError => re
235
- can_retry = job.attempts + 1 < job.inferred_max_attempts
236
- callback_type = can_retry ? :retry : :error
237
- self.class.lifecycle.run_callbacks(callback_type, self, job, re) do
238
- handle_failed_job(job, re)
239
- end
240
- rescue SystemExit => se
241
- # There wasn't really a failure here so no callbacks and whatnot needed,
242
- # still reschedule the job though.
243
- job.reschedule(se)
244
- rescue Exception => e
245
- self.class.lifecycle.run_callbacks(:error, self, job, e) do
246
- handle_failed_job(job, e)
247
257
  end
258
+ count
248
259
  end
249
- count
250
- end
251
260
 
252
- def perform_batch(parent_job)
253
- batch = parent_job.payload_object
254
- if batch.mode == :serial
261
+ def perform_batch(parent_job)
262
+ batch = parent_job.payload_object
263
+ return unless batch.mode == :serial
264
+
255
265
  batch.jobs.each do |job|
256
266
  job.source = parent_job.source
257
267
  job.create_and_lock!(name)
@@ -261,72 +271,72 @@ class Worker
261
271
  end
262
272
  batch.items.size
263
273
  end
264
- end
265
274
 
266
- def handle_failed_job(job, error)
267
- job.last_error = "#{error.message}\n#{error.backtrace.join("\n")}"
268
- logger.error("Failed with #{error.class} [#{error.message}] (#{job.attempts} attempts)")
269
- job.reschedule(error)
270
- end
275
+ def handle_failed_job(job, error)
276
+ job.last_error = "#{error.message}\n#{error.backtrace.join("\n")}"
277
+ logger.error("Failed with #{error.class} [#{error.message}] (#{job.attempts} attempts)")
278
+ job.reschedule(error)
279
+ end
271
280
 
272
- def id
273
- Process.pid
274
- end
281
+ def id
282
+ Process.pid
283
+ end
275
284
 
276
- def log_job(job, format = :short)
277
- case format
278
- when :long
279
- "#{job.full_name} #{ Settings.job_detailed_log_format.call(job) }"
280
- else
281
- job.full_name
285
+ def log_job(job, format = :short)
286
+ case format
287
+ when :long
288
+ "#{job.full_name} #{Settings.job_detailed_log_format.call(job)}"
289
+ else
290
+ job.full_name
291
+ end
282
292
  end
283
- end
284
293
 
285
- # set up the session context information, so that it gets logged with the job log lines
286
- # also set up a unique tmpdir, which will get removed at the end of the job.
287
- def configure_for_job(job)
288
- previous_tmpdir = ENV['TMPDIR']
294
+ # set up the session context information, so that it gets logged with the job log lines
295
+ # also set up a unique tmpdir, which will get removed at the end of the job.
296
+ def configure_for_job(job)
297
+ previous_tmpdir = ENV["TMPDIR"]
289
298
 
290
- self.class.running_job(job) do
291
- dir = Dir.mktmpdir("job-#{job.id}-#{self.name.gsub(/[^\w\.]/, '.')}-")
292
- begin
293
- ENV['TMPDIR'] = dir
294
- yield
295
- ensure
296
- FileUtils.remove_entry(dir, true)
299
+ self.class.running_job(job) do
300
+ dir = Dir.mktmpdir("job-#{job.id}-#{name.gsub(/[^\w.]/, '.')}-")
301
+ begin
302
+ ENV["TMPDIR"] = dir
303
+ yield
304
+ ensure
305
+ FileUtils.remove_entry(dir, true)
306
+ end
297
307
  end
308
+ ensure
309
+ ENV["TMPDIR"] = previous_tmpdir
298
310
  end
299
- ensure
300
- ENV['TMPDIR'] = previous_tmpdir
301
- end
302
-
303
- def health_check
304
- @health_check ||= HealthCheck.build(
305
- type: @health_check_type,
306
- worker_name: name,
307
- config: @health_check_config
308
- )
309
- end
310
311
 
311
- # `sample` reports KB, not B
312
- if File.directory?("/proc")
313
- # linux w/ proc fs
314
- LINUX_PAGE_SIZE = (size = `getconf PAGESIZE`.to_i; size > 0 ? size : 4096)
315
- def sample_memory
316
- s = File.read("/proc/#{Process.pid}/statm").to_i rescue 0
317
- s * LINUX_PAGE_SIZE / 1024
312
+ def health_check
313
+ @health_check ||= HealthCheck.build(
314
+ type: @health_check_type,
315
+ worker_name: name,
316
+ config: @health_check_config
317
+ )
318
318
  end
319
- else
320
- # generic unix solution
321
- def sample_memory
322
- if Rails.env.test?
323
- 0
324
- else
325
- # hmm this is actually resident set size, doesn't include swapped-to-disk
326
- # memory.
327
- `ps -o rss= -p #{Process.pid}`.to_i
319
+
320
+ # `sample` reports KB, not B
321
+ if File.directory?("/proc")
322
+ # linux w/ proc fs
323
+ LINUX_PAGE_SIZE = (size = `getconf PAGESIZE`.to_i
324
+ size.positive? ? size : 4096)
325
+ def sample_memory
326
+ s = File.read("/proc/#{Process.pid}/statm").to_i rescue 0
327
+ s * LINUX_PAGE_SIZE / 1024
328
+ end
329
+ else
330
+ # generic unix solution
331
+ def sample_memory
332
+ if Rails.env.test?
333
+ 0
334
+ else
335
+ # hmm this is actually resident set size, doesn't include swapped-to-disk
336
+ # memory.
337
+ `ps -o rss= -p #{Process.pid}`.to_i
338
+ end
328
339
  end
329
340
  end
330
341
  end
331
342
  end
332
- end
@@ -2,36 +2,37 @@
2
2
 
3
3
  # New definitions for YAML to aid in serialization and deserialization of delayed jobs.
4
4
 
5
- require 'yaml'
5
+ require "yaml"
6
6
 
7
7
  # These two added domain types are for backwards compatibility with jobs created
8
8
  # using the old syck tags, as syck didn't have built-in module/class dumping. We
9
9
  # now use Psych's built-in tags, which are `!ruby/module` and `!ruby/class`. At
10
10
  # some point we can remove these, once there are no more jobs in any queues with
11
11
  # these tags.
12
- Psych.add_domain_type("ruby/object", "Module") do |type, val|
12
+ Psych.add_domain_type("ruby/object", "Module") do |_type, val|
13
13
  val.constantize
14
14
  end
15
- Psych.add_domain_type("ruby/object", "Class") do |type, val|
15
+ Psych.add_domain_type("ruby/object", "Class") do |_type, val|
16
16
  val.constantize
17
17
  end
18
18
 
19
19
  # Tell YAML how to intelligently load ActiveRecord objects, using the
20
20
  # database rather than just serializing their attributes to the YAML. This
21
21
  # ensures the object is up to date when we use it in the job.
22
- class ActiveRecord::Base
23
- def encode_with(coder)
24
- if id.nil?
25
- raise("Can't serialize unsaved ActiveRecord object for delayed job: #{self.inspect}")
22
+ module ActiveRecord
23
+ class Base
24
+ def encode_with(coder)
25
+ raise("Can't serialize unsaved ActiveRecord object for delayed job: #{inspect}") if id.nil?
26
+
27
+ coder.scalar("!ruby/ActiveRecord:#{self.class.name}", id.to_s)
26
28
  end
27
- coder.scalar("!ruby/ActiveRecord:#{self.class.name}", id.to_s)
28
29
  end
29
30
  end
30
31
 
31
32
  module Delayed
32
33
  module PsychExt
33
34
  module ToRuby
34
- def visit_Psych_Nodes_Scalar(object)
35
+ def visit_Psych_Nodes_Scalar(object) # rubocop:disable Naming/MethodName
35
36
  case object.tag
36
37
  when %r{^!ruby/ActiveRecord:(.+)$}
37
38
  begin
@@ -50,7 +51,8 @@ module Delayed
50
51
  end
51
52
 
52
53
  def resolve_class(klass_name)
53
- return nil if !klass_name || klass_name.empty?
54
+ return nil if klass_name.blank?
55
+
54
56
  klass_name.constantize
55
57
  rescue
56
58
  super