inst-jobs 1.0.4 → 2.0.0
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/lib/delayed/periodic.rb +14 -4
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/worker/health_check.rb +34 -19
- data/spec/delayed/periodic_spec.rb +39 -0
- data/spec/delayed/worker/health_check_spec.rb +9 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d674b7da21caf04eb87ff9823ed549c93a901219669316090d088f0699564e59
|
4
|
+
data.tar.gz: 021456d34f12eff8cc988db866018d701fc77ffdbb57e9fb308fc1bd25a91ecb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ad78cfdd9026db24b714c532c8ee837a875e443afc375909f0c130e3cfbf87d1f872344f982d931838bfa6649a2f1edc59430f6444a2baee08f8afb568015cfc
|
7
|
+
data.tar.gz: e2b127477f0687958178505628b9544aa5c49e7aa1d0ceef32892250aa26aeb1c77f12bcacd6682e17c2bc379f987b154a0f982e029852432c39f7b3a5335df8
|
data/lib/delayed/periodic.rb
CHANGED
@@ -49,10 +49,20 @@ class Periodic
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def enqueue
|
52
|
-
Delayed::Job.enqueue(self,
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
Delayed::Job.enqueue(self, **enqueue_args)
|
53
|
+
end
|
54
|
+
|
55
|
+
def enqueue_args
|
56
|
+
inferred_args = {
|
57
|
+
max_attempts: 1,
|
58
|
+
run_at: @cron.next_time(Delayed::Periodic.now).utc.to_time,
|
59
|
+
singleton: (@job_args[:singleton] == false ? nil : tag),
|
60
|
+
# yes, checking for whether it is actually the boolean literal false,
|
61
|
+
# which means the consuming code really does not want this job to be
|
62
|
+
# a singleton at all.
|
63
|
+
on_conflict: :patient
|
64
|
+
}
|
65
|
+
@job_args.merge(inferred_args)
|
56
66
|
end
|
57
67
|
|
58
68
|
def perform
|
data/lib/delayed/version.rb
CHANGED
@@ -22,31 +22,46 @@ module Delayed
|
|
22
22
|
|
23
23
|
def reschedule_abandoned_jobs
|
24
24
|
return if Settings.worker_health_check_type == :none
|
25
|
+
Delayed::Job.transaction do
|
26
|
+
# this job is a special case, and is not a singleton
|
27
|
+
# because if it gets wiped out suddenly during execution
|
28
|
+
# it can't go clean up it's abandoned self. Therefore,
|
29
|
+
# we try to get an advisory lock when it runs. If we succeed,
|
30
|
+
# no other job is trying to do this right now (and if we abandon the
|
31
|
+
# job, the transaction will end, releasing the advisory lock).
|
32
|
+
result = attempt_advisory_lock
|
33
|
+
return unless result
|
34
|
+
checker = Worker::HealthCheck.build(
|
35
|
+
type: Settings.worker_health_check_type,
|
36
|
+
config: Settings.worker_health_check_config,
|
37
|
+
worker_name: 'cleanup-crew'
|
38
|
+
)
|
39
|
+
live_workers = checker.live_workers
|
25
40
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
# double check that the job is still there. locked_by will immediately be reset
|
40
|
-
# to nil in this transaction by Job#reschedule
|
41
|
-
next unless Delayed::Job.where(id: job, locked_by: job.locked_by).update_all(locked_by: "abandoned job cleanup") == 1
|
42
|
-
job.reschedule
|
41
|
+
Delayed::Job.running_jobs.each do |job|
|
42
|
+
# prefetched jobs have their own way of automatically unlocking themselves
|
43
|
+
next if job.locked_by.start_with?("prefetch:")
|
44
|
+
unless live_workers.include?(job.locked_by)
|
45
|
+
begin
|
46
|
+
Delayed::Job.transaction do
|
47
|
+
# double check that the job is still there. locked_by will immediately be reset
|
48
|
+
# to nil in this transaction by Job#reschedule
|
49
|
+
next unless Delayed::Job.where(id: job, locked_by: job.locked_by).update_all(locked_by: "abandoned job cleanup") == 1
|
50
|
+
job.reschedule
|
51
|
+
end
|
52
|
+
rescue
|
53
|
+
::Rails.logger.error "Failure rescheduling abandoned job #{job.id} #{$!.inspect}"
|
43
54
|
end
|
44
|
-
rescue
|
45
|
-
::Rails.logger.error "Failure rescheduling abandoned job #{job.id} #{$!.inspect}"
|
46
55
|
end
|
47
56
|
end
|
48
57
|
end
|
49
58
|
end
|
59
|
+
|
60
|
+
def attempt_advisory_lock
|
61
|
+
lock_name = "Delayed::Worker::HealthCheck#reschedule_abandoned_jobs"
|
62
|
+
output = ActiveRecord::Base.connection.execute("SELECT pg_try_advisory_xact_lock(half_md5_as_bigint('#{lock_name}'));")
|
63
|
+
output.getvalue(0, 0)
|
64
|
+
end
|
50
65
|
end
|
51
66
|
|
52
67
|
attr_accessor :config, :worker_name
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe Delayed::Periodic do
|
6
|
+
around(:each) do |block|
|
7
|
+
# make sure we can use ".cron" and
|
8
|
+
# such safely without leaking global state
|
9
|
+
prev_sched = Delayed::Periodic.scheduled
|
10
|
+
prev_ovr = Delayed::Periodic.overrides
|
11
|
+
Delayed::Periodic.scheduled = {}
|
12
|
+
Delayed::Periodic.overrides = {}
|
13
|
+
block.call
|
14
|
+
ensure
|
15
|
+
Delayed::Periodic.scheduled = prev_sched
|
16
|
+
Delayed::Periodic.overrides = prev_ovr
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".cron" do
|
20
|
+
let(:job_name){ 'just a test'}
|
21
|
+
it "provides a tag by default for periodic jobs" do
|
22
|
+
Delayed::Periodic.cron job_name, '*/10 * * * *' do
|
23
|
+
# no-op
|
24
|
+
end
|
25
|
+
instance = Delayed::Periodic.scheduled[job_name]
|
26
|
+
expect(instance).to_not be_nil
|
27
|
+
expect(instance.enqueue_args[:singleton]).to eq("periodic: just a test")
|
28
|
+
end
|
29
|
+
|
30
|
+
it "uses no singleton if told to skip" do
|
31
|
+
Delayed::Periodic.cron job_name, '*/10 * * * *', {singleton: false} do
|
32
|
+
# no-op
|
33
|
+
end
|
34
|
+
instance = Delayed::Periodic.scheduled[job_name]
|
35
|
+
expect(instance).to_not be_nil
|
36
|
+
expect(instance.enqueue_args[:singleton]).to be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -107,6 +107,15 @@ RSpec.describe Delayed::Worker::HealthCheck do
|
|
107
107
|
@dead_job.reload
|
108
108
|
expect(@dead_job.locked_by).to eq 'prefetch:some_node'
|
109
109
|
end
|
110
|
+
|
111
|
+
it "bails immediately if advisory lock already taken" do
|
112
|
+
allow(Delayed::Worker::HealthCheck).to receive(:attempt_advisory_lock).and_return(false)
|
113
|
+
Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
|
114
|
+
@dead_job.reload
|
115
|
+
expect(@dead_job.run_at.to_i).to eq(initial_run_at.to_i)
|
116
|
+
expect(@dead_job.locked_at).to_not be_nil
|
117
|
+
expect(@dead_job.locked_by).to_not be_nil
|
118
|
+
end
|
110
119
|
end
|
111
120
|
|
112
121
|
describe '#initialize' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inst-jobs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Luetke
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-12-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -412,6 +412,7 @@ files:
|
|
412
412
|
- spec/delayed/cli_spec.rb
|
413
413
|
- spec/delayed/daemon_spec.rb
|
414
414
|
- spec/delayed/message_sending_spec.rb
|
415
|
+
- spec/delayed/periodic_spec.rb
|
415
416
|
- spec/delayed/server_spec.rb
|
416
417
|
- spec/delayed/settings_spec.rb
|
417
418
|
- spec/delayed/work_queue/in_process_spec.rb
|
@@ -448,7 +449,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
448
449
|
requirements:
|
449
450
|
- - ">="
|
450
451
|
- !ruby/object:Gem::Version
|
451
|
-
version: '2.
|
452
|
+
version: '2.6'
|
452
453
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
453
454
|
requirements:
|
454
455
|
- - ">="
|
@@ -480,6 +481,7 @@ test_files:
|
|
480
481
|
- spec/delayed/cli_spec.rb
|
481
482
|
- spec/delayed/daemon_spec.rb
|
482
483
|
- spec/delayed/worker_spec.rb
|
484
|
+
- spec/delayed/periodic_spec.rb
|
483
485
|
- spec/delayed/message_sending_spec.rb
|
484
486
|
- spec/delayed/settings_spec.rb
|
485
487
|
- spec/delayed/work_queue/in_process_spec.rb
|