inst-jobs 2.0.0 → 2.2.1
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/backend/base.rb +9 -1
- data/lib/delayed/lifecycle.rb +1 -0
- data/lib/delayed/periodic.rb +1 -4
- data/lib/delayed/pool.rb +31 -0
- data/lib/delayed/settings.rb +1 -0
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/worker/consul_health_check.rb +17 -20
- data/lib/delayed/worker/health_check.rb +7 -6
- data/lib/delayed/worker.rb +46 -25
- data/spec/delayed/periodic_spec.rb +1 -9
- data/spec/delayed/worker/consul_health_check_spec.rb +23 -36
- data/spec/delayed/worker_spec.rb +23 -3
- data/spec/spec_helper.rb +3 -0
- metadata +30 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9550c353f31dc1d34a15993bdfbf279d87979ebb625ae776fb6727d7dc9e897e
|
4
|
+
data.tar.gz: 379f8faac5d3369551b4012a00f522d7871a4001776120c4e02535b70bdef8a3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dbb7a9366256f16a0fd7fbf22938d94c7754cdd3d9189d3d7d94e0d8deda59859ec4822f1e3c1d05cc7a2a67c8501a79c83d7b0b69f91fd106d9b24b4f35b06
|
7
|
+
data.tar.gz: 637e09a985feeef6144e5b172a04c8ceee5980eed3b1b49f2597e33bbf26522c43244bc2778905ba400cf0de6485166258103e09aa7a765e261f8971b89b2c06
|
data/lib/delayed/backend/base.rb
CHANGED
@@ -87,6 +87,10 @@ module Delayed
|
|
87
87
|
batches[batch_enqueue_args] << kwargs
|
88
88
|
return true
|
89
89
|
else
|
90
|
+
if kwargs[:on_conflict].present?
|
91
|
+
Delayed::Logging.logger.warn("[DELAYED_JOB] WARNING: providing 'on_conflict' as an option to a non-singleton job will have no effect. Discarding.")
|
92
|
+
kwargs.delete(:on_conflict)
|
93
|
+
end
|
90
94
|
job = self.create(**kwargs)
|
91
95
|
end
|
92
96
|
|
@@ -178,6 +182,10 @@ module Delayed
|
|
178
182
|
expires_at && (self.class.db_time_now >= expires_at)
|
179
183
|
end
|
180
184
|
|
185
|
+
def inferred_max_attempts
|
186
|
+
self.max_attempts || Delayed::Settings.max_attempts
|
187
|
+
end
|
188
|
+
|
181
189
|
# Reschedule the job in the future (when a job fails).
|
182
190
|
# Uses an exponential scale depending on the number of failed attempts.
|
183
191
|
def reschedule(error = nil, time = nil)
|
@@ -190,7 +198,7 @@ module Delayed
|
|
190
198
|
|
191
199
|
self.attempts += 1 unless return_code == :unlock
|
192
200
|
|
193
|
-
if self.attempts >=
|
201
|
+
if self.attempts >= self.inferred_max_attempts
|
194
202
|
permanent_failure error || "max attempts reached"
|
195
203
|
elsif expired?
|
196
204
|
permanent_failure error || "job has expired"
|
data/lib/delayed/lifecycle.rb
CHANGED
data/lib/delayed/periodic.rb
CHANGED
@@ -56,10 +56,7 @@ class Periodic
|
|
56
56
|
inferred_args = {
|
57
57
|
max_attempts: 1,
|
58
58
|
run_at: @cron.next_time(Delayed::Periodic.now).utc.to_time,
|
59
|
-
singleton:
|
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.
|
59
|
+
singleton: tag,
|
63
60
|
on_conflict: :patient
|
64
61
|
}
|
65
62
|
@job_args.merge(inferred_args)
|
data/lib/delayed/pool.rb
CHANGED
@@ -39,6 +39,7 @@ class Pool
|
|
39
39
|
Process.wait unlock_pid
|
40
40
|
|
41
41
|
spawn_periodic_auditor
|
42
|
+
spawn_abandoned_job_cleanup
|
42
43
|
spawn_all_workers
|
43
44
|
say "Workers spawned"
|
44
45
|
join
|
@@ -111,6 +112,34 @@ class Pool
|
|
111
112
|
end
|
112
113
|
end
|
113
114
|
|
115
|
+
def spawn_abandoned_job_cleanup
|
116
|
+
return if Settings.disable_abandoned_job_cleanup
|
117
|
+
cleanup_interval_in_minutes = 60
|
118
|
+
@abandoned_cleanup_thread = Thread.new do
|
119
|
+
# every hour (staggered by process)
|
120
|
+
# check for dead jobs and cull them.
|
121
|
+
# Will actually be more often based on the
|
122
|
+
# number of worker nodes in the pool. This will actually
|
123
|
+
# be a max of N times per hour where N is the number of workers,
|
124
|
+
# but they won't overrun each other because the health check
|
125
|
+
# takes an advisory lock internally
|
126
|
+
sleep(rand(cleanup_interval_in_minutes * 60))
|
127
|
+
loop do
|
128
|
+
schedule_abandoned_job_cleanup
|
129
|
+
sleep(cleanup_interval_in_minutes * 60)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def schedule_abandoned_job_cleanup
|
135
|
+
pid = fork_with_reconnects do
|
136
|
+
# we want to avoid db connections in the main pool process
|
137
|
+
$0 = "delayed_abandoned_job_cleanup"
|
138
|
+
Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
|
139
|
+
end
|
140
|
+
workers[pid] = :abandoned_job_cleanup
|
141
|
+
end
|
142
|
+
|
114
143
|
def spawn_periodic_auditor
|
115
144
|
return if Settings.disable_periodic_jobs
|
116
145
|
|
@@ -217,6 +246,8 @@ class Pool
|
|
217
246
|
case worker
|
218
247
|
when :periodic_audit
|
219
248
|
say "ran auditor: #{worker}"
|
249
|
+
when :abandoned_job_cleanup
|
250
|
+
say "ran cleanup: #{worker}"
|
220
251
|
when :work_queue
|
221
252
|
say "work queue exited, restarting", :info
|
222
253
|
spawn_work_queue
|
data/lib/delayed/settings.rb
CHANGED
data/lib/delayed/version.rb
CHANGED
@@ -9,52 +9,49 @@ module Delayed
|
|
9
9
|
class ConsulHealthCheck < HealthCheck
|
10
10
|
self.type_name = :consul
|
11
11
|
|
12
|
-
CONSUL_CONFIG_KEYS = %w{url
|
12
|
+
CONSUL_CONFIG_KEYS = %w{url acl_token}.map(&:freeze).freeze
|
13
13
|
DEFAULT_SERVICE_NAME = 'inst-jobs_worker'.freeze
|
14
|
-
attr_reader :
|
14
|
+
attr_reader :service_client, :health_client
|
15
15
|
|
16
16
|
def initialize(*, **)
|
17
17
|
super
|
18
18
|
# Because we don't want the consul client to be a hard dependency we're
|
19
19
|
# only requiring it once it's absolutely needed
|
20
|
-
require '
|
20
|
+
require 'diplomat'
|
21
21
|
|
22
22
|
if config.keys.any? { |k| CONSUL_CONFIG_KEYS.include?(k) }
|
23
|
-
consul_config =
|
23
|
+
consul_config = Diplomat::Configuration.new.tap do |conf|
|
24
24
|
CONSUL_CONFIG_KEYS.each do |key|
|
25
25
|
conf.send("#{key}=", config[key]) if config[key]
|
26
26
|
end
|
27
27
|
end
|
28
|
-
@
|
29
|
-
@
|
28
|
+
@service_client = Diplomat::Service.new(configuration: consul_config)
|
29
|
+
@health_client = Diplomat::Health.new(configuration: consul_config)
|
30
30
|
else
|
31
|
-
@
|
32
|
-
@
|
31
|
+
@service_client = Diplomat::Service.new
|
32
|
+
@health_client = Diplomat::Health.new
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def start
|
37
|
-
|
37
|
+
@service_client.register({
|
38
38
|
id: worker_name,
|
39
39
|
name: service_name,
|
40
|
+
check: check_attributes
|
40
41
|
})
|
41
|
-
service.add_check(check_attributes)
|
42
|
-
response = @agent_client.register_service(service)
|
43
|
-
response.ok?
|
44
42
|
end
|
45
43
|
|
46
44
|
def stop
|
47
|
-
|
48
|
-
response.ok? || response.not_found?
|
45
|
+
@service_client.deregister(worker_name)
|
49
46
|
end
|
50
47
|
|
51
48
|
def live_workers
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
# Filter out critical workers (probably nodes failing their serf health check)
|
50
|
+
live_nodes = @health_client.service(service_name, {
|
51
|
+
filter: 'not Checks.Status == critical'
|
52
|
+
})
|
53
|
+
|
54
|
+
live_nodes.map { |n| n.Service['ID']}
|
58
55
|
end
|
59
56
|
|
60
57
|
private
|
@@ -23,12 +23,13 @@ module Delayed
|
|
23
23
|
def reschedule_abandoned_jobs
|
24
24
|
return if Settings.worker_health_check_type == :none
|
25
25
|
Delayed::Job.transaction do
|
26
|
-
# this
|
26
|
+
# this action is a special case, and SHOULD NOT be a periodic job
|
27
27
|
# because if it gets wiped out suddenly during execution
|
28
28
|
# it can't go clean up it's abandoned self. Therefore,
|
29
|
-
# we
|
30
|
-
#
|
31
|
-
#
|
29
|
+
# we expect it to get run from it's own process forked from the job pool
|
30
|
+
# and we try to get an advisory lock when it runs. If we succeed,
|
31
|
+
# no other worker is trying to do this right now (and if we abandon the
|
32
|
+
# operation, the transaction will end, releasing the advisory lock).
|
32
33
|
result = attempt_advisory_lock
|
33
34
|
return unless result
|
34
35
|
checker = Worker::HealthCheck.build(
|
@@ -59,8 +60,8 @@ module Delayed
|
|
59
60
|
|
60
61
|
def attempt_advisory_lock
|
61
62
|
lock_name = "Delayed::Worker::HealthCheck#reschedule_abandoned_jobs"
|
62
|
-
|
63
|
-
|
63
|
+
conn = ActiveRecord::Base.connection
|
64
|
+
conn.select_value("SELECT pg_try_advisory_xact_lock(#{conn.quote_table_name('half_md5_as_bigint')}('#{lock_name}'));")
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
data/lib/delayed/worker.rb
CHANGED
@@ -3,6 +3,17 @@
|
|
3
3
|
module Delayed
|
4
4
|
|
5
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
|
6
17
|
|
7
18
|
require 'tmpdir'
|
8
19
|
require 'set'
|
@@ -94,7 +105,11 @@ class Worker
|
|
94
105
|
end
|
95
106
|
|
96
107
|
def exit?
|
97
|
-
|
108
|
+
!!@exit || parent_exited?
|
109
|
+
end
|
110
|
+
|
111
|
+
def parent_exited?
|
112
|
+
@parent_pid && @parent_pid != Process.ppid
|
98
113
|
end
|
99
114
|
|
100
115
|
def wake_up
|
@@ -198,32 +213,38 @@ class Worker
|
|
198
213
|
end
|
199
214
|
|
200
215
|
def perform(job)
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
229
|
+
end
|
230
|
+
job.destroy
|
213
231
|
end
|
214
|
-
job
|
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)
|
215
247
|
end
|
216
|
-
logger.info("Completed #{log_job(job)} #{"%.0fms" % (runtime * 1000)}")
|
217
|
-
end
|
218
|
-
count
|
219
|
-
rescue SystemExit => se
|
220
|
-
# There wasn't really a failure here so no callbacks and whatnot needed,
|
221
|
-
# still reschedule the job though.
|
222
|
-
job.reschedule(se)
|
223
|
-
count
|
224
|
-
rescue Exception => e
|
225
|
-
self.class.lifecycle.run_callbacks(:error, self, job, e) do
|
226
|
-
handle_failed_job(job, e)
|
227
248
|
end
|
228
249
|
count
|
229
250
|
end
|
@@ -14,6 +14,7 @@ RSpec.describe Delayed::Periodic do
|
|
14
14
|
ensure
|
15
15
|
Delayed::Periodic.scheduled = prev_sched
|
16
16
|
Delayed::Periodic.overrides = prev_ovr
|
17
|
+
Delayed::Job.delete_all
|
17
18
|
end
|
18
19
|
|
19
20
|
describe ".cron" do
|
@@ -26,14 +27,5 @@ RSpec.describe Delayed::Periodic do
|
|
26
27
|
expect(instance).to_not be_nil
|
27
28
|
expect(instance.enqueue_args[:singleton]).to eq("periodic: just a test")
|
28
29
|
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
30
|
end
|
39
31
|
end
|
@@ -1,76 +1,63 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
-
require 'imperium'
|
5
4
|
|
6
5
|
RSpec.describe Delayed::Worker::ConsulHealthCheck do
|
7
6
|
let(:health_check) { Delayed::Worker::ConsulHealthCheck.new(worker_name: 'foobar') }
|
8
7
|
|
9
|
-
# can't use a verifying double for the response because the methods we're
|
10
|
-
# tryig to stub are actually on HTTP::Message
|
11
|
-
let(:response) { double('Imperium::Response') }
|
12
|
-
let(:agent_client) { instance_double(Imperium::Agent) }
|
13
|
-
|
14
|
-
before do
|
15
|
-
allow(Imperium::Agent).to receive(:default_client).and_return(agent_client)
|
16
|
-
end
|
17
|
-
|
18
8
|
describe '#initialize' do
|
19
|
-
it 'must use
|
9
|
+
it 'must use a default service client when the config is mostly empty' do
|
20
10
|
check = Delayed::Worker::ConsulHealthCheck.new(worker_name: 'foobar')
|
21
|
-
expect(check.
|
11
|
+
expect(check.service_client.configuration.url.to_s).to eq 'http://localhost:8500'
|
22
12
|
end
|
23
13
|
|
24
|
-
it 'must create a new
|
14
|
+
it 'must create a new service API client when the config has relevant keys set' do
|
25
15
|
check = Delayed::Worker::ConsulHealthCheck.new(worker_name: 'foobar', config: {url: 'http://consul.example.com:8500'})
|
26
|
-
|
27
|
-
expect(
|
28
|
-
expect(agent_client.config.url.to_s).to eq 'http://consul.example.com:8500'
|
16
|
+
service_client = check.service_client
|
17
|
+
expect(service_client.configuration.url.to_s).to eq 'http://consul.example.com:8500'
|
29
18
|
end
|
30
19
|
end
|
31
20
|
|
32
21
|
describe '#start' do
|
33
22
|
it 'must register this process as a service with consul' do
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
.and_return(response)
|
23
|
+
stub = stub_request(:put, "localhost:8500/v1/agent/service/register")
|
24
|
+
.with(body: hash_including({id: 'foobar' }))
|
25
|
+
|
38
26
|
health_check.start
|
27
|
+
|
28
|
+
expect(stub).to have_been_requested
|
39
29
|
end
|
40
30
|
|
41
31
|
|
42
32
|
it 'must supply a args style check' do
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
expect(check.args).to_not be_nil
|
47
|
-
response
|
48
|
-
}
|
33
|
+
stub = stub_request(:put, "localhost:8500/v1/agent/service/register")
|
34
|
+
.with(body: hash_including({check: WebMock::API.hash_including({args: anything})}))
|
35
|
+
|
49
36
|
health_check.start
|
37
|
+
|
38
|
+
expect(stub).to have_been_requested
|
50
39
|
end
|
51
40
|
|
52
41
|
it 'must include the docker container id when the docker option is set to true' do
|
42
|
+
stub = stub_request(:put, "localhost:8500/v1/agent/service/register")
|
43
|
+
.with(body: hash_including({check: WebMock::API.hash_including({docker_container_id: anything})}))
|
44
|
+
|
53
45
|
local_health_check = Delayed::Worker::ConsulHealthCheck.new(
|
54
46
|
worker_name: 'foobar',
|
55
47
|
config: {docker: true}
|
56
48
|
)
|
57
|
-
allow(response).to receive(:ok?).and_return(true)
|
58
|
-
allow(agent_client).to receive(:register_service) { |service|
|
59
|
-
check = service.checks.first
|
60
|
-
expect(check.docker_container_id).to_not be_nil
|
61
|
-
response
|
62
|
-
}
|
63
49
|
local_health_check.start
|
50
|
+
|
51
|
+
expect(stub).to have_been_requested
|
64
52
|
end
|
65
53
|
end
|
66
54
|
|
67
55
|
describe '#stop' do
|
68
56
|
it 'must deregister the service from consul' do
|
69
|
-
|
70
|
-
|
71
|
-
.with(health_check.worker_name)
|
72
|
-
.and_return(response)
|
57
|
+
stub = stub_request(:put, "localhost:8500/v1/agent/service/deregister/foobar")
|
58
|
+
|
73
59
|
health_check.stop
|
60
|
+
expect(stub).to have_been_requested
|
74
61
|
end
|
75
62
|
end
|
76
63
|
end
|
data/spec/delayed/worker_spec.rb
CHANGED
@@ -6,6 +6,11 @@ describe Delayed::Worker do
|
|
6
6
|
let(:worker_config) { {
|
7
7
|
queue: "test", min_priority: 1, max_priority: 2, stuff: "stuff",
|
8
8
|
}.freeze }
|
9
|
+
let(:job_attrs) { {
|
10
|
+
id: 42, name: "testjob", full_name: "testfullname", :last_error= => nil,
|
11
|
+
attempts: 1, reschedule: nil, :expired? => false,
|
12
|
+
payload_object: {}, priority: 25
|
13
|
+
}.freeze }
|
9
14
|
subject { described_class.new(worker_config.dup) }
|
10
15
|
|
11
16
|
after { Delayed::Worker.lifecycle.reset! }
|
@@ -14,9 +19,24 @@ describe Delayed::Worker do
|
|
14
19
|
it "fires off an error callback when a job raises an exception" do
|
15
20
|
fired = false
|
16
21
|
Delayed::Worker.lifecycle.before(:error) {|worker, exception| fired = true}
|
17
|
-
job = double(
|
18
|
-
subject.perform(job)
|
22
|
+
job = double(job_attrs)
|
23
|
+
output_count = subject.perform(job)
|
19
24
|
expect(fired).to be_truthy
|
25
|
+
expect(output_count).to eq(1)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "uses the retry callback for a retriable exception" do
|
29
|
+
error_fired = retry_fired = false
|
30
|
+
Delayed::Worker.lifecycle.before(:error) {|worker, exception| error_fired = true }
|
31
|
+
Delayed::Worker.lifecycle.before(:retry) {|worker, exception| retry_fired = true}
|
32
|
+
job = Delayed::Job.new(payload_object: {}, priority: 25, strand: "test_jobs", max_attempts: 3)
|
33
|
+
expect(job).to receive(:invoke_job) do
|
34
|
+
raise Delayed::RetriableError, "that's all this job does"
|
35
|
+
end
|
36
|
+
output_count = subject.perform(job)
|
37
|
+
expect(error_fired).to be_falsey
|
38
|
+
expect(retry_fired).to be_truthy
|
39
|
+
expect(output_count).to eq(1)
|
20
40
|
end
|
21
41
|
|
22
42
|
it "reloads" do
|
@@ -35,7 +55,7 @@ describe Delayed::Worker do
|
|
35
55
|
expect(ActionDispatch::Reloader).to receive(:prepare!).once
|
36
56
|
expect(ActionDispatch::Reloader).to receive(:cleanup!).once
|
37
57
|
end
|
38
|
-
job = double(
|
58
|
+
job = double(job_attrs)
|
39
59
|
subject.perform(job)
|
40
60
|
end
|
41
61
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -7,6 +7,8 @@ require 'database_cleaner'
|
|
7
7
|
require 'rack/test'
|
8
8
|
require 'test_after_commit' if ::Rails.version < '5'
|
9
9
|
require 'timecop'
|
10
|
+
require 'webmock/rspec'
|
11
|
+
|
10
12
|
require 'pry'
|
11
13
|
require 'byebug'
|
12
14
|
|
@@ -19,6 +21,7 @@ RSpec.configure do |config|
|
|
19
21
|
config.before(:suite) do
|
20
22
|
DatabaseCleaner.strategy = :transaction
|
21
23
|
DatabaseCleaner.clean_with(:truncation)
|
24
|
+
WebMock.disable_net_connect!
|
22
25
|
end
|
23
26
|
|
24
27
|
config.before(:each) do |example|
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inst-jobs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Luetke
|
8
8
|
- Brian Palmer
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-02-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -172,33 +172,33 @@ dependencies:
|
|
172
172
|
- !ruby/object:Gem::Version
|
173
173
|
version: 1.6.1
|
174
174
|
- !ruby/object:Gem::Dependency
|
175
|
-
name:
|
175
|
+
name: diplomat
|
176
176
|
requirement: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- - "
|
178
|
+
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
180
|
+
version: 2.5.1
|
181
181
|
type: :development
|
182
182
|
prerelease: false
|
183
183
|
version_requirements: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- - "
|
185
|
+
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
187
|
+
version: 2.5.1
|
188
188
|
- !ruby/object:Gem::Dependency
|
189
189
|
name: pg
|
190
190
|
requirement: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- - "
|
192
|
+
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: '
|
194
|
+
version: '0'
|
195
195
|
type: :development
|
196
196
|
prerelease: false
|
197
197
|
version_requirements: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
|
-
- - "
|
199
|
+
- - ">="
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: '
|
201
|
+
version: '0'
|
202
202
|
- !ruby/object:Gem::Dependency
|
203
203
|
name: pry
|
204
204
|
requirement: !ruby/object:Gem::Requirement
|
@@ -311,6 +311,20 @@ dependencies:
|
|
311
311
|
- - '='
|
312
312
|
- !ruby/object:Gem::Version
|
313
313
|
version: 0.7.1
|
314
|
+
- !ruby/object:Gem::Dependency
|
315
|
+
name: webmock
|
316
|
+
requirement: !ruby/object:Gem::Requirement
|
317
|
+
requirements:
|
318
|
+
- - ">="
|
319
|
+
- !ruby/object:Gem::Version
|
320
|
+
version: '0'
|
321
|
+
type: :development
|
322
|
+
prerelease: false
|
323
|
+
version_requirements: !ruby/object:Gem::Requirement
|
324
|
+
requirements:
|
325
|
+
- - ">="
|
326
|
+
- !ruby/object:Gem::Version
|
327
|
+
version: '0'
|
314
328
|
- !ruby/object:Gem::Dependency
|
315
329
|
name: wwtd
|
316
330
|
requirement: !ruby/object:Gem::Requirement
|
@@ -325,7 +339,7 @@ dependencies:
|
|
325
339
|
- - "~>"
|
326
340
|
- !ruby/object:Gem::Version
|
327
341
|
version: 1.4.0
|
328
|
-
description:
|
342
|
+
description:
|
329
343
|
email:
|
330
344
|
- brianp@instructure.com
|
331
345
|
executables:
|
@@ -441,7 +455,7 @@ files:
|
|
441
455
|
homepage: https://github.com/instructure/inst-jobs
|
442
456
|
licenses: []
|
443
457
|
metadata: {}
|
444
|
-
post_install_message:
|
458
|
+
post_install_message:
|
445
459
|
rdoc_options: []
|
446
460
|
require_paths:
|
447
461
|
- lib
|
@@ -456,8 +470,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
456
470
|
- !ruby/object:Gem::Version
|
457
471
|
version: '0'
|
458
472
|
requirements: []
|
459
|
-
rubygems_version: 3.
|
460
|
-
signing_key:
|
473
|
+
rubygems_version: 3.1.4
|
474
|
+
signing_key:
|
461
475
|
specification_version: 4
|
462
476
|
summary: Instructure-maintained fork of delayed_job
|
463
477
|
test_files:
|