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,50 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
5
  RSpec.describe Delayed::Worker::ConsulHealthCheck do
6
- let(:health_check) { Delayed::Worker::ConsulHealthCheck.new(worker_name: 'foobar') }
6
+ let(:health_check) { described_class.new(worker_name: "foobar") }
7
7
 
8
- describe '#initialize' do
9
- it 'must use a default service client when the config is mostly empty' do
10
- check = Delayed::Worker::ConsulHealthCheck.new(worker_name: 'foobar')
11
- expect(check.service_client.configuration.url.to_s).to eq 'http://localhost:8500'
8
+ describe "#initialize" do
9
+ it "must use a default service client when the config is mostly empty" do
10
+ check = described_class.new(worker_name: "foobar")
11
+ expect(check.service_client.configuration.url.to_s).to eq "http://localhost:8500"
12
12
  end
13
13
 
14
- it 'must create a new service API client when the config has relevant keys set' do
15
- check = Delayed::Worker::ConsulHealthCheck.new(worker_name: 'foobar', config: {url: 'http://consul.example.com:8500'})
14
+ it "must create a new service API client when the config has relevant keys set" do
15
+ check = described_class.new(worker_name: "foobar",
16
+ config: { url: "http://consul.example.com:8500" })
16
17
  service_client = check.service_client
17
- expect(service_client.configuration.url.to_s).to eq 'http://consul.example.com:8500'
18
+ expect(service_client.configuration.url.to_s).to eq "http://consul.example.com:8500"
18
19
  end
19
20
  end
20
21
 
21
- describe '#start' do
22
- it 'must register this process as a service with consul' do
22
+ describe "#start" do
23
+ it "must register this process as a service with consul" do
23
24
  stub = stub_request(:put, "localhost:8500/v1/agent/service/register")
24
- .with(body: hash_including({id: 'foobar' }))
25
+ .with(body: hash_including({ id: "foobar" }))
25
26
 
26
27
  health_check.start
27
28
 
28
29
  expect(stub).to have_been_requested
29
30
  end
30
31
 
31
-
32
- it 'must supply a args style check' do
32
+ it "must supply a args style check" do
33
33
  stub = stub_request(:put, "localhost:8500/v1/agent/service/register")
34
- .with(body: hash_including({check: WebMock::API.hash_including({args: anything})}))
34
+ .with(body: hash_including({ check: WebMock::API.hash_including({ args: anything }) }))
35
35
 
36
36
  health_check.start
37
37
 
38
38
  expect(stub).to have_been_requested
39
39
  end
40
40
 
41
- it 'must include the docker container id when the docker option is set to true' do
41
+ it "must include the docker container id when the docker option is set to true" do
42
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})}))
43
+ .with(body: hash_including({ check: WebMock::API.hash_including({ docker_container_id: anything }) }))
44
44
 
45
- local_health_check = Delayed::Worker::ConsulHealthCheck.new(
46
- worker_name: 'foobar',
47
- config: {docker: true}
45
+ local_health_check = described_class.new(
46
+ worker_name: "foobar",
47
+ config: { docker: true }
48
48
  )
49
49
  local_health_check.start
50
50
 
@@ -52,8 +52,8 @@ RSpec.describe Delayed::Worker::ConsulHealthCheck do
52
52
  end
53
53
  end
54
54
 
55
- describe '#stop' do
56
- it 'must deregister the service from consul' do
55
+ describe "#stop" do
56
+ it "must deregister the service from consul" do
57
57
  stub = stub_request(:put, "localhost:8500/v1/agent/service/deregister/foobar")
58
58
 
59
59
  health_check.stop
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
3
+ require "spec_helper"
4
4
 
5
5
  RSpec.describe Delayed::Worker::HealthCheck do
6
6
  let(:klass) { Class.new(Delayed::Worker::HealthCheck) { self.type_name = :test } }
@@ -10,116 +10,124 @@ RSpec.describe Delayed::Worker::HealthCheck do
10
10
  end
11
11
 
12
12
  after do
13
- Delayed::Worker::HealthCheck.subclasses.delete(klass)
13
+ described_class.subclasses.delete(klass)
14
14
  end
15
15
 
16
16
  it "must maintain a list of its subclasses" do
17
17
  klass
18
- expect(Delayed::Worker::HealthCheck.subclasses).to include klass
18
+ expect(described_class.subclasses).to include klass
19
19
  end
20
20
 
21
- describe '.build(type:, config: {})' do
22
- it 'must select the concrete class to use by the type_name in the subclass' do
23
- check = Delayed::Worker::HealthCheck.build(type: 'test', worker_name: 'foobar')
21
+ describe ".build(type:, config: {})" do
22
+ it "must select the concrete class to use by the type_name in the subclass" do
23
+ check = described_class.build(type: "test", worker_name: "foobar")
24
24
  expect(check).to be_a(klass)
25
25
  end
26
26
 
27
27
  it "must raise ArgumentError when the specified type doesn't exist" do
28
- expect {
29
- Delayed::Worker::HealthCheck.build(type: 'nope', config: {worker_name: 'foobar'})
30
- }.to raise_error ArgumentError
28
+ expect do
29
+ described_class.build(type: "nope", config: { worker_name: "foobar" })
30
+ end.to raise_error ArgumentError
31
31
  end
32
32
 
33
- it 'must initiaize the specified class using the supplied config' do
34
- config = {foo: 'bar'}.with_indifferent_access
35
- check = Delayed::Worker::HealthCheck.build(type: 'test', worker_name: 'foobar', config: config)
33
+ it "must initiaize the specified class using the supplied config" do
34
+ config = { foo: "bar" }.with_indifferent_access
35
+ check = described_class.build(type: "test", worker_name: "foobar", config: config)
36
36
  expect(check.config).to eq config
37
37
  end
38
38
  end
39
39
 
40
- describe '.reschedule_abandoned_jobs' do
41
- let(:klass) { Class.new(Delayed::Worker::HealthCheck) {
42
- self.type_name = :fake
43
- class << self
44
- attr_accessor :live_workers
40
+ describe ".reschedule_abandoned_jobs" do
41
+ let(:klass) do
42
+ Class.new(Delayed::Worker::HealthCheck) do
43
+ self.type_name = :fake
44
+ class << self
45
+ attr_accessor :live_workers
46
+ end
47
+
48
+ def live_workers
49
+ self.class.live_workers
50
+ end
45
51
  end
52
+ end
46
53
 
47
- def live_workers
48
- self.class.live_workers
49
- end
50
- } }
51
-
52
- let(:initial_run_at) { Time.zone.now }
54
+ let(:initial_run_at) { 10.minutes.ago }
53
55
 
54
56
  before do
55
- klass.live_workers = %w{alive}
57
+ klass.live_workers = %w[alive]
56
58
  Delayed.select_backend(Delayed::Backend::ActiveRecord::Job)
57
59
 
58
60
  2.times { Delayed::Job.enqueue(SimpleJob.new, run_at: initial_run_at, max_attempts: 4) }
59
61
  @alive_job = Delayed::Job.first
60
62
  @alive_job.update!({
61
- locked_by: 'alive',
62
- locked_at: initial_run_at
63
- })
63
+ locked_by: "alive",
64
+ locked_at: initial_run_at
65
+ })
64
66
  @dead_job = Delayed::Job.last
65
67
  @dead_job.update!({
66
- locked_by: 'dead',
67
- locked_at: initial_run_at
68
- })
68
+ locked_by: "dead",
69
+ locked_at: initial_run_at
70
+ })
69
71
  Delayed::Settings.worker_health_check_type = :fake
70
72
  Delayed::Settings.worker_health_check_config = {}
71
73
  end
72
74
 
73
75
  after do
74
- Delayed::Worker::HealthCheck.subclasses.delete(klass)
76
+ described_class.subclasses.delete(klass)
75
77
  Delayed::Settings.worker_health_check_type = :none
76
78
  Delayed::Settings.worker_health_check_config = {}
77
79
  end
78
80
 
79
- it 'must leave jobs locked by live workers alone' do
80
- Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
81
+ it "must leave jobs locked by live workers alone" do
82
+ described_class.reschedule_abandoned_jobs
81
83
  @alive_job.reload
82
84
  expect(@alive_job.run_at.to_i).to eq initial_run_at.to_i
83
85
  expect(@alive_job.locked_at.to_i).to eq initial_run_at.to_i
84
- expect(@alive_job.locked_by).to eq 'alive'
86
+ expect(@alive_job.locked_by).to eq "alive"
85
87
  end
86
88
 
87
- it 'must reschedule jobs locked by dead workers' do
88
- Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
89
+ it "must reschedule jobs locked by dead workers" do
90
+ described_class.reschedule_abandoned_jobs
89
91
  @dead_job.reload
90
92
  expect(@dead_job.run_at).to be > initial_run_at
91
93
  expect(@dead_job.locked_at).to be_nil
92
94
  expect(@dead_job.locked_by).to be_nil
93
95
  end
94
96
 
95
- it 'ignores jobs that are re-locked after fetching from db' do
96
- Delayed::Job.where(id: @dead_job).update_all(locked_by: 'someone_else')
97
- allow(Delayed::Job).to receive(:running_jobs).and_return([@dead_job])
98
- Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
97
+ it "ignores jobs that are re-locked after fetching from db" do
98
+ Delayed::Job.where(id: @dead_job).update_all(locked_by: "someone_else")
99
+ # we need to return @dead_job itself, which doesn't match the database
100
+ jobs_scope = double
101
+ allow(jobs_scope).to receive(:where).and_return(jobs_scope)
102
+ allow(jobs_scope).to receive(:not).and_return(jobs_scope)
103
+ allow(jobs_scope).to receive(:limit).and_return(jobs_scope)
104
+ allow(jobs_scope).to receive(:to_a).and_return([@dead_job], [])
105
+ allow(Delayed::Job).to receive(:running_jobs).and_return(jobs_scope)
106
+ described_class.reschedule_abandoned_jobs
99
107
  @dead_job.reload
100
- expect(@dead_job.locked_by).to eq 'someone_else'
108
+ expect(@dead_job.locked_by).to eq "someone_else"
101
109
  end
102
110
 
103
- it 'ignores jobs that are prefetched' do
104
- Delayed::Job.where(id: @dead_job).update_all(locked_by: 'prefetch:some_node')
105
- allow(Delayed::Job).to receive(:running_jobs).and_return([@dead_job])
106
- Delayed::Worker::HealthCheck.reschedule_abandoned_jobs
111
+ it "ignores jobs that are prefetched" do
112
+ Delayed::Job.where(id: @dead_job).update_all(locked_by: "prefetch:some_node")
113
+ allow(Delayed::Job).to receive(:running_jobs).and_return(Delayed::Job.where(id: @dead_job.id))
114
+ described_class.reschedule_abandoned_jobs
107
115
  @dead_job.reload
108
- expect(@dead_job.locked_by).to eq 'prefetch:some_node'
116
+ expect(@dead_job.locked_by).to eq "prefetch:some_node"
109
117
  end
110
118
 
111
119
  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
120
+ allow(Delayed::Job).to receive(:attempt_advisory_lock).and_return(false)
121
+ described_class.reschedule_abandoned_jobs
114
122
  @dead_job.reload
115
123
  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
124
+ expect(@dead_job.locked_at).not_to be_nil
125
+ expect(@dead_job.locked_by).not_to be_nil
118
126
  end
119
127
  end
120
128
 
121
- describe '#initialize' do
122
- it 'must raise ArgumentError when the worker name is not supplied' do
129
+ describe "#initialize" do
130
+ it "must raise ArgumentError when the worker name is not supplied" do
123
131
  expect { klass.new }.to raise_error ArgumentError
124
132
  end
125
133
  end
@@ -3,22 +3,27 @@
3
3
  require_relative "../spec_helper"
4
4
 
5
5
  describe Delayed::Worker do
6
- let(:worker_config) { {
7
- queue: "test", min_priority: 1, max_priority: 2, stuff: "stuff",
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 }
14
6
  subject { described_class.new(worker_config.dup) }
15
7
 
16
- after { Delayed::Worker.lifecycle.reset! }
8
+ let(:worker_config) do
9
+ {
10
+ queue: "test", min_priority: 1, max_priority: 2, stuff: "stuff"
11
+ }.freeze
12
+ end
13
+ let(:job_attrs) do
14
+ {
15
+ id: 42, name: "testjob", full_name: "testfullname", :last_error= => nil,
16
+ attempts: 1, reschedule: nil, :expired? => false,
17
+ payload_object: {}, priority: 25
18
+ }.freeze
19
+ end
20
+
21
+ after { described_class.lifecycle.reset! }
17
22
 
18
23
  describe "#perform" do
19
24
  it "fires off an error callback when a job raises an exception" do
20
25
  fired = false
21
- Delayed::Worker.lifecycle.before(:error) {|worker, exception| fired = true}
26
+ described_class.lifecycle.before(:error) { |_worker, _exception| fired = true }
22
27
  job = double(job_attrs)
23
28
  output_count = subject.perform(job)
24
29
  expect(fired).to be_truthy
@@ -27,8 +32,8 @@ describe Delayed::Worker do
27
32
 
28
33
  it "uses the retry callback for a retriable exception" do
29
34
  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}
35
+ described_class.lifecycle.before(:error) { |_worker, _exception| error_fired = true }
36
+ described_class.lifecycle.before(:retry) { |_worker, _exception| retry_fired = true }
32
37
  job = Delayed::Job.new(payload_object: {}, priority: 25, strand: "test_jobs", max_attempts: 3)
33
38
  expect(job).to receive(:invoke_job) do
34
39
  raise Delayed::RetriableError, "that's all this job does"
@@ -40,15 +45,13 @@ describe Delayed::Worker do
40
45
  end
41
46
 
42
47
  it "reloads" do
43
- fakeApplication = double('Rails.application',
44
- config: double('Rails.application.config',
45
- cache_classes: false,
46
- reload_classes_only_on_change: false
47
- ),
48
- reloader: double()
49
- )
48
+ fake_application = double("Rails.application",
49
+ config: double("Rails.application.config",
50
+ cache_classes: false,
51
+ reload_classes_only_on_change: false),
52
+ reloader: double)
50
53
 
51
- allow(Rails).to receive(:application).and_return(fakeApplication)
54
+ allow(Rails).to receive(:application).and_return(fake_application)
52
55
  if Rails::VERSION::MAJOR >= 5
53
56
  expect(Rails.application.reloader).to receive(:reload!).once
54
57
  else
@@ -61,7 +64,7 @@ describe Delayed::Worker do
61
64
  end
62
65
 
63
66
  describe "#log_job" do
64
- around(:each) do |block|
67
+ around do |block|
65
68
  prev_logger = Delayed::Settings.job_detailed_log_format
66
69
  block.call
67
70
  Delayed::Settings.job_detailed_log_format = prev_logger
@@ -73,11 +76,11 @@ describe Delayed::Worker do
73
76
  short_log_format = subject.log_job(job, :short)
74
77
  expect(short_log_format).to eq("RSpec::Mocks::Double")
75
78
  long_format = subject.log_job(job, :long)
76
- expect(long_format).to eq("RSpec::Mocks::Double {\"priority\":25,\"attempts\":0,\"created_at\":null,\"tag\":\"RSpec::Mocks::Double#perform\",\"max_attempts\":null,\"strand\":\"test_jobs\",\"source\":null}")
79
+ expect(long_format).to eq("RSpec::Mocks::Double {\"priority\":25,\"attempts\":0,\"created_at\":null,\"tag\":\"RSpec::Mocks::Double#perform\",\"max_attempts\":null,\"strand\":\"test_jobs\",\"source\":null}") # rubocop:disable Layout/LineLength
77
80
  end
78
81
 
79
82
  it "logging format can be changed with settings" do
80
- Delayed::Settings.job_detailed_log_format = ->(job){ "override format #{job.strand}"}
83
+ Delayed::Settings.job_detailed_log_format = ->(job) { "override format #{job.strand}" }
81
84
  payload = double(perform: nil)
82
85
  job = Delayed::Job.new(payload_object: payload, priority: 25, strand: "test_jobs")
83
86
  short_log_format = subject.log_job(job, :short)
@@ -89,8 +92,8 @@ describe Delayed::Worker do
89
92
 
90
93
  describe "#run" do
91
94
  it "passes extra config options through to the WorkQueue" do
92
- expect(subject.work_queue).to receive(:get_and_lock_next_available).
93
- with(subject.name, worker_config).and_return(nil)
95
+ expect(subject.work_queue).to receive(:get_and_lock_next_available)
96
+ .with(subject.name, worker_config).and_return(nil)
94
97
  subject.run
95
98
  end
96
99
  end
data/spec/sample_jobs.rb CHANGED
@@ -1,49 +1,79 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class SimpleJob
4
- cattr_accessor :runs; self.runs = 0
5
- def perform; @@runs += 1; end
4
+ class << self
5
+ attr_accessor :runs
6
+ end
7
+
8
+ self.runs = 0
9
+
10
+ def perform
11
+ self.class.runs += 1
12
+ end
6
13
  end
7
14
 
8
15
  class ErrorJob
9
- cattr_accessor :runs; self.runs = 0
10
- def perform; raise 'did not work'; end
16
+ class << self
17
+ attr_accessor :runs, :last_error, :failure_runs, :permanent_failure_runs
18
+ end
11
19
 
12
- cattr_accessor :last_error; self.last_error = nil
20
+ self.runs = 0
21
+ def perform
22
+ raise "did not work"
23
+ end
13
24
 
14
- cattr_accessor :failure_runs; self.failure_runs = 0
15
- def on_failure(error); @@last_error = error; @@failure_runs += 1; end
25
+ self.last_error = nil
26
+ self.failure_runs = 0
27
+ def on_failure(error)
28
+ self.class.last_error = error
29
+ self.class.failure_runs += 1
30
+ end
16
31
 
17
- cattr_accessor :permanent_failure_runs; self.permanent_failure_runs = 0
18
- def on_permanent_failure(error); @@last_error = error; @@permanent_failure_runs += 1; end
32
+ self.permanent_failure_runs = 0
33
+ def on_permanent_failure(error)
34
+ self.class.last_error = error
35
+ self.class.permanent_failure_runs += 1
36
+ end
19
37
  end
20
38
 
21
39
  class UnlockJob
22
40
  attr_accessor :times_to_unlock
41
+
23
42
  def initialize(times_to_unlock)
24
43
  @times_to_unlock = times_to_unlock
25
44
  end
26
45
 
27
- def perform; raise SystemExit, 'raising to trigger on_failure'; end
46
+ def perform
47
+ raise SystemExit, "raising to trigger on_failure"
48
+ end
28
49
 
29
- def on_failure(error)
50
+ def on_failure(_error)
30
51
  times_to_unlock -= 1
31
52
  :unlock if times_to_unlock <= 0
32
53
  end
33
54
  end
34
55
 
35
56
  class LongRunningJob
36
- def perform; sleep 250; end
57
+ def perform
58
+ sleep 250
59
+ end
37
60
  end
38
61
 
39
62
  module M
40
63
  class ModuleJob
41
- cattr_accessor :runs; self.runs = 0
42
- def perform; @@runs += 1; end
64
+ class << self
65
+ attr_accessor :runs
66
+ end
67
+
68
+ cattr_accessor :runs
69
+ self.runs = 0
70
+ def perform
71
+ self.class.runs += 1
72
+ end
43
73
  end
44
74
  end
45
75
 
46
76
  class DeserializeErrorJob < SimpleJob; end
47
- Psych.add_domain_type("ruby/object", "DeserializeErrorJob") do |_type, val|
77
+ Psych.add_domain_type("ruby/object", "DeserializeErrorJob") do |_type, _val|
48
78
  raise "error deserializing"
49
79
  end
@@ -1,98 +1,105 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- shared_examples_for 'Delayed::Batch' do
3
+ shared_examples_for "Delayed::Batch" do
4
4
  context "batching" do
5
- it "should batch up all deferrable delayed methods" do
5
+ it "batches up all deferrable delayed methods" do
6
6
  later = 1.hour.from_now
7
- Delayed::Batch.serial_batch {
8
- "string".delay(ignore_transaction: true).size.should be true
9
- "string".delay(run_at: later, ignore_transaction: true).reverse.should be_truthy # won't be batched, it'll get its own job
10
- "string".delay(ignore_transaction: true).gsub(/./, "!").should be_truthy
11
- }
7
+ Delayed::Batch.serial_batch do
8
+ expect("string".delay(ignore_transaction: true).size).to be true
9
+ # won't be batched, it'll get its own job
10
+ expect("string".delay(run_at: later, ignore_transaction: true).reverse).to be_truthy
11
+ expect("string".delay(ignore_transaction: true).gsub(/./, "!")).to be_truthy
12
+ end
12
13
  batch_jobs = Delayed::Job.find_available(5)
13
14
  regular_jobs = Delayed::Job.list_jobs(:future, 5)
14
- regular_jobs.size.should == 1
15
- regular_jobs.first.batch?.should == false
16
- batch_jobs.size.should == 1
15
+ expect(regular_jobs.size).to eq(1)
16
+ expect(regular_jobs.first.batch?).to eq(false)
17
+ expect(batch_jobs.size).to eq(1)
17
18
  batch_job = batch_jobs.first
18
- batch_job.batch?.should == true
19
- batch_job.payload_object.mode.should == :serial
20
- batch_job.payload_object.jobs.map { |j| [j.payload_object.object, j.payload_object.method, j.payload_object.args] }.should == [
21
- ["string", :size, []],
22
- ["string", :gsub, [/./, "!"]]
23
- ]
19
+ expect(batch_job.batch?).to eq(true)
20
+ expect(batch_job.payload_object.mode).to eq(:serial)
21
+ expect(batch_job.payload_object.jobs.map do |j|
22
+ [j.payload_object.object, j.payload_object.method, j.payload_object.args]
23
+ end).to eq([
24
+ [
25
+ "string", :size, []
26
+ ],
27
+ [
28
+ "string", :gsub, [
29
+ /./, "!"
30
+ ]
31
+ ]
32
+ ])
24
33
  end
25
34
 
26
- it "should not let you invoke it directly" do
27
- later = 1.hour.from_now
28
- Delayed::Batch.serial_batch {
29
- "string".delay(ignore_transaction: true).size.should be true
30
- "string".delay(ignore_transaction: true).gsub(/./, "!").should be true
31
- }
32
- Delayed::Job.jobs_count(:current).should == 1
35
+ it "does not let you invoke it directly" do
36
+ Delayed::Batch.serial_batch do
37
+ expect("string".delay(ignore_transaction: true).size).to be true
38
+ expect("string".delay(ignore_transaction: true).gsub(/./, "!")).to be true
39
+ end
40
+ expect(Delayed::Job.jobs_count(:current)).to eq(1)
33
41
  job = Delayed::Job.find_available(1).first
34
- expect{ job.invoke_job }.to raise_error(RuntimeError)
42
+ expect { job.invoke_job }.to raise_error(RuntimeError)
35
43
  end
36
44
 
37
- it "should create valid jobs" do
38
- Delayed::Batch.serial_batch {
39
- "string".delay(ignore_transaction: true).size.should be true
40
- "string".delay(ignore_transaction: true).gsub(/./, "!").should be true
41
- }
42
- Delayed::Job.jobs_count(:current).should == 1
45
+ it "creates valid jobs" do
46
+ Delayed::Batch.serial_batch do
47
+ expect("string".delay(ignore_transaction: true).size).to be true
48
+ expect("string".delay(ignore_transaction: true).gsub(/./, "!")).to be true
49
+ end
50
+ expect(Delayed::Job.jobs_count(:current)).to eq(1)
43
51
 
44
52
  batch_job = Delayed::Job.find_available(1).first
45
- batch_job.batch?.should == true
53
+ expect(batch_job.batch?).to eq(true)
46
54
  jobs = batch_job.payload_object.jobs
47
- jobs.size.should == 2
48
- jobs[0].should be_new_record
49
- jobs[0].payload_object.class.should == Delayed::PerformableMethod
50
- jobs[0].payload_object.method.should == :size
51
- jobs[0].payload_object.args.should == []
52
- jobs[0].payload_object.perform.should == 6
53
- jobs[1].should be_new_record
54
- jobs[1].payload_object.class.should == Delayed::PerformableMethod
55
- jobs[1].payload_object.method.should == :gsub
56
- jobs[1].payload_object.args.should == [/./, "!"]
57
- jobs[1].payload_object.perform.should == "!!!!!!"
55
+ expect(jobs.size).to eq(2)
56
+ expect(jobs[0]).to be_new_record
57
+ expect(jobs[0].payload_object.class).to eq(Delayed::PerformableMethod)
58
+ expect(jobs[0].payload_object.method).to eq(:size)
59
+ expect(jobs[0].payload_object.args).to eq([])
60
+ expect(jobs[0].payload_object.perform).to eq(6)
61
+ expect(jobs[1]).to be_new_record
62
+ expect(jobs[1].payload_object.class).to eq(Delayed::PerformableMethod)
63
+ expect(jobs[1].payload_object.method).to eq(:gsub)
64
+ expect(jobs[1].payload_object.args).to eq([/./, "!"])
65
+ expect(jobs[1].payload_object.perform).to eq("!!!!!!")
58
66
  end
59
67
 
60
- it "should create a different batch for each priority" do
61
- later = 1.hour.from_now
62
- Delayed::Batch.serial_batch {
63
- "string".delay(priority: Delayed::LOW_PRIORITY, ignore_transaction: true).size.should be true
64
- "string".delay(ignore_transaction: true).gsub(/./, "!").should be true
65
- }
66
- Delayed::Job.jobs_count(:current).should == 2
68
+ it "creates a different batch for each priority" do
69
+ Delayed::Batch.serial_batch do
70
+ expect("string".delay(priority: Delayed::LOW_PRIORITY, ignore_transaction: true).size).to be true
71
+ expect("string".delay(ignore_transaction: true).gsub(/./, "!")).to be true
72
+ end
73
+ expect(Delayed::Job.jobs_count(:current)).to eq(2)
67
74
  end
68
75
 
69
- it "should use the given priority for all, if specified" do
70
- Delayed::Batch.serial_batch(:priority => 11) {
71
- "string".delay(priority: 20, ignore_transaction: true).size.should be true
72
- "string".delay(priority: 15, ignore_transaction: true).gsub(/./, "!").should be true
73
- }
74
- Delayed::Job.jobs_count(:current).should == 1
75
- Delayed::Job.find_available(1).first.priority.should == 11
76
+ it "uses the given priority for all, if specified" do
77
+ Delayed::Batch.serial_batch(priority: 11) do
78
+ expect("string".delay(priority: 20, ignore_transaction: true).size).to be true
79
+ expect("string".delay(priority: 15, ignore_transaction: true).gsub(/./, "!")).to be true
80
+ end
81
+ expect(Delayed::Job.jobs_count(:current)).to eq(1)
82
+ expect(Delayed::Job.find_available(1).first.priority).to eq(11)
76
83
  end
77
84
 
78
- it "should just create the job, if there's only one in the batch" do
79
- Delayed::Batch.serial_batch(:priority => 11) {
80
- "string".delay(ignore_transaction: true).size.should be true
81
- }
82
- Delayed::Job.jobs_count(:current).should == 1
83
- Delayed::Job.find_available(1).first.tag.should == "String#size"
84
- Delayed::Job.find_available(1).first.priority.should == 11
85
+ it "justs create the job, if there's only one in the batch" do
86
+ Delayed::Batch.serial_batch(priority: 11) do
87
+ expect("string".delay(ignore_transaction: true).size).to be true
88
+ end
89
+ expect(Delayed::Job.jobs_count(:current)).to eq(1)
90
+ expect(Delayed::Job.find_available(1).first.tag).to eq("String#size")
91
+ expect(Delayed::Job.find_available(1).first.priority).to eq(11)
85
92
  end
86
93
 
87
- it "should list a job only once when the same call is made multiple times" do
88
- Delayed::Batch.serial_batch(:priority => 11) {
94
+ it "lists a job only once when the same call is made multiple times" do
95
+ Delayed::Batch.serial_batch(priority: 11) do
89
96
  "string".delay(ignore_transaction: true).size
90
97
  "string".delay(ignore_transaction: true).gsub(/./, "!")
91
98
  "string".delay(ignore_transaction: true).size
92
- }
99
+ end
93
100
  batch_job = Delayed::Job.find_available(1).first
94
101
  jobs = batch_job.payload_object.jobs
95
- jobs.size.should == 2
102
+ expect(jobs.size).to eq(2)
96
103
  end
97
104
  end
98
105
  end