delayed_job_groups_plugin 0.4.2 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0754808400681b63e14fc299849af001fd1657bf492fdd56947e00519eaba89
4
- data.tar.gz: c30c2bde41bcb5a9c374cdb3bab3c9c75ebf7ea5d50e63696fba296600f13985
3
+ metadata.gz: d9fb6a8ff3bc2cada4bb9a8f76382ca323eed8539188646efccd80a1b767acac
4
+ data.tar.gz: 90e5ea6437fc1485d8ca26a34062e3a30de989c7f8d8751643280d3830d12c79
5
5
  SHA512:
6
- metadata.gz: 53c683f2825c99da19e8307c7a1d8b42f91dcad430f77a2f3fcd2cb90cef2ab5e1a2a4693166da75f3cc51e72a614688ae92edbdddcd39626c3b4bdf95a09722
7
- data.tar.gz: a6a273708961cbd9922382400c441c97f570768283db311c129120f27cfb414b1265227667895e65d2385a194f2bfc05b1e8d09f1489341fa85dc76309a10cda
6
+ metadata.gz: 943569571301edf9a43a3a73c967fb165fb5fcda2e9576a3d0ace3b2a5a3bf2a4fe46e73cc812d0498ec09b2bf2fa8ffc56bee70741f5e29d30aa4ca653ce822
7
+ data.tar.gz: 0f26bbf975f3d5c727aa639afe5ea1e974fd0c8623031e62fbec78467237c8b44ea31d28f977c8dd74fb15779f8cd951a530504a9e24181ae69579ccde29a7a8
@@ -0,0 +1,81 @@
1
+ version: 2.1
2
+ jobs:
3
+ lint:
4
+ docker:
5
+ - image: salsify/ruby_ci:2.6.6
6
+ working_directory: ~/delayed_job_groups
7
+ steps:
8
+ - checkout
9
+ - restore_cache:
10
+ keys:
11
+ - v1-gems-ruby-2.6.6-{{ checksum "delayed_job_groups.gemspec" }}-{{ checksum "Gemfile" }}
12
+ - v1-gems-ruby-2.6.6-
13
+ - run:
14
+ name: Install Gems
15
+ command: |
16
+ if ! bundle check --path=vendor/bundle; then
17
+ bundle install --path=vendor/bundle --jobs=4 --retry=3
18
+ bundle clean
19
+ fi
20
+ - save_cache:
21
+ key: v1-gems-ruby-2.6.6-{{ checksum "delayed_job_groups.gemspec" }}-{{ checksum "Gemfile" }}
22
+ paths:
23
+ - "vendor/bundle"
24
+ - "gemfiles/vendor/bundle"
25
+ - run:
26
+ name: Run Rubocop
27
+ command: bundle exec rubocop
28
+ test:
29
+ parameters:
30
+ gemfile:
31
+ type: string
32
+ ruby_version:
33
+ type: string
34
+ docker:
35
+ - image: salsify/ruby_ci:<< parameters.ruby_version >>
36
+ environment:
37
+ CIRCLE_TEST_REPORTS: "test-results"
38
+ BUNDLE_GEMFILE: << parameters.gemfile >>
39
+ working_directory: ~/delayed_job_groups
40
+ steps:
41
+ - checkout
42
+ - restore_cache:
43
+ keys:
44
+ - v1-gems-ruby-<< parameters.ruby_version >>-{{ checksum "delayed_job_groups.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
45
+ - v1-gems-ruby-<< parameters.ruby_version >>-
46
+ - run:
47
+ name: Install Gems
48
+ command: |
49
+ if ! bundle check --path=vendor/bundle; then
50
+ bundle install --path=vendor/bundle --jobs=4 --retry=3
51
+ bundle clean
52
+ fi
53
+ - save_cache:
54
+ key: v1-gems-ruby-<< parameters.ruby_version >>-{{ checksum "delayed_job_groups.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
55
+ paths:
56
+ - "vendor/bundle"
57
+ - "gemfiles/vendor/bundle"
58
+ - run:
59
+ name: Run Tests
60
+ command: |
61
+ bundle exec rspec --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/rspec/junit.xml --format progress spec
62
+ - store_test_results:
63
+ path: "test-results"
64
+ workflows:
65
+ build:
66
+ jobs:
67
+ - lint
68
+ - test:
69
+ matrix:
70
+ parameters:
71
+ gemfile:
72
+ - "gemfiles/rails_5.2.gemfile"
73
+ - "gemfiles/rails_6.0.gemfile"
74
+ - "gemfiles/rails_6.1.gemfile"
75
+ ruby_version:
76
+ - "2.6.6"
77
+ - "2.7.2"
78
+ - "3.0.0"
79
+ exclude:
80
+ - gemfile: "gemfiles/rails_5.2.gemfile"
81
+ ruby_version: "3.0.0"
data/.rubocop.yml CHANGED
@@ -2,7 +2,10 @@ inherit_gem:
2
2
  salsify_rubocop: conf/rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.3
5
+ TargetRubyVersion: 2.6
6
+ Exclude:
7
+ - 'vendor/**/*'
8
+ - 'gemfiles/**/*'
6
9
 
7
10
  Style/FrozenStringLiteralComment:
8
11
  Enabled: true
data/Appraisals CHANGED
@@ -1,30 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise 'rails-4.2' do
4
- gem 'sqlite3', '~> 1.3.6'
5
- gem 'activerecord', '4.2.10'
6
- gem 'activesupport', '4.2.10'
7
- end
8
-
9
- appraise 'rails-5.0' do
10
- gem 'sqlite3', '~> 1.3.6'
11
- gem 'activerecord', '5.0.7'
12
- gem 'activesupport', '5.0.7'
13
- end
14
-
15
- appraise 'rails-5.1' do
16
- gem 'sqlite3', '~> 1.3.6'
17
- gem 'activerecord', '5.1.6'
18
- gem 'activesupport', '5.1.6'
19
- end
20
-
21
3
  appraise 'rails-5.2' do
22
4
  gem 'sqlite3', '~> 1.3.6'
23
- gem 'activerecord', '5.2.1 '
24
- gem 'activesupport', '5.2.1 '
5
+ gem 'activerecord', '5.2.1'
6
+ gem 'activesupport', '5.2.1'
25
7
  end
26
8
 
27
9
  appraise 'rails-6.0' do
28
10
  gem 'activerecord', '6.0.3'
29
11
  gem 'activesupport', '6.0.3'
30
12
  end
13
+
14
+ appraise 'rails-6.1' do
15
+ gem 'activerecord', '6.1.0'
16
+ gem 'activesupport', '6.1.0'
17
+ end
data/CHANGELOG.md CHANGED
@@ -1,4 +1,24 @@
1
1
  # Changelog
2
+ ### 0.7.0
3
+ * Add support for ruby 3
4
+ * Drop support for ruby < 2.6
5
+
6
+ ### 0.6.2
7
+ * Defer including extension until delayed_job_active_record is loaded
8
+
9
+ ### 0.6.1
10
+ * Fix job_group_id `belongs_to` behavior when `config.active_record.belongs_to_required_by_default` is enabled.
11
+
12
+ ### 0.6.0
13
+ * Add support for Rails 6.1.
14
+
15
+ ### 0.5.0
16
+ * Drop support for Ruby 2.3 and 2.4.
17
+ * Drop support for Rails < 5.2.
18
+ * Bugfix for rails version in generated migration files
19
+
20
+ ### 0.4.3
21
+ * Bugfix for `on_completion_job` when `failure_cancels_group` is set to false.
2
22
 
3
23
  ### 0.4.2
4
24
  * Add support for Rails 6.0.
data/README.md CHANGED
@@ -100,7 +100,8 @@ job_group.cancel
100
100
 
101
101
  Configuration to allow failed jobs not to cancel the group
102
102
  ```ruby
103
- # We can optionally pass options that will allow jobs to fail without cancelling the group
103
+ # We can optionally pass options that will allow jobs to fail without cancelling the group.
104
+ # This also allows the on_completion job to fire once all jobs have either succeeded or failed.
104
105
  job_group = Delayed::JobGroups::JobGroup.create!(failure_cancels_group: false)
105
106
  ```
106
107
 
@@ -1,7 +1,6 @@
1
-
2
1
  # frozen_string_literal: true
3
2
 
4
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
5
  require 'delayed/job_groups/version'
7
6
 
@@ -19,22 +18,24 @@ Gem::Specification.new do |spec|
19
18
  spec.test_files = Dir.glob('spec/**/*')
20
19
  spec.require_paths = ['lib']
21
20
 
22
- spec.required_ruby_version = '>= 2.3'
21
+ spec.required_ruby_version = '>= 2.6'
23
22
 
24
23
  spec.add_dependency 'delayed_job', '>= 4.1'
25
24
  spec.add_dependency 'delayed_job_active_record', '>= 4.1'
26
25
 
27
- spec.post_install_message = 'See https://github.com/salsify/delayed_job_groups_plugin#installation for upgrade/installation notes.'
26
+ spec.post_install_message = 'See https://github.com/salsify/delayed_job_groups_plugin#installation '\
27
+ 'for upgrade/installation notes.'
28
28
 
29
29
  spec.add_development_dependency 'appraisal'
30
- spec.add_dependency 'activerecord', '>= 4.2', '< 6.1'
31
- spec.add_development_dependency 'coveralls'
30
+ spec.add_dependency 'activerecord', '>= 5.2', '< 7'
31
+ spec.add_development_dependency 'coveralls_reborn', '>= 0.18.0'
32
32
  spec.add_development_dependency 'database_cleaner', '>= 1.2'
33
33
  spec.add_development_dependency 'mime-types'
34
34
  spec.add_development_dependency 'rake'
35
35
  spec.add_development_dependency 'rspec', '~> 3'
36
36
  spec.add_development_dependency 'rspec-its'
37
- spec.add_development_dependency 'salsify_rubocop', '0.52.1.1'
37
+ spec.add_development_dependency 'rspec_junit_formatter'
38
+ spec.add_development_dependency 'salsify_rubocop', '~> 1.0.1'
38
39
  spec.add_development_dependency 'simplecov'
39
40
  spec.add_development_dependency 'sqlite3'
40
41
  spec.add_development_dependency 'timecop'
@@ -3,7 +3,7 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "sqlite3", "~> 1.3.6"
6
- gem "activerecord", "5.2.1 "
7
- gem "activesupport", "5.2.1 "
6
+ gem "activerecord", "5.2.1"
7
+ gem "activesupport", "5.2.1"
8
8
 
9
9
  gemspec path: "../"
@@ -2,8 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "sqlite3", "~> 1.3.6"
6
- gem "activerecord", "5.0.7"
7
- gem "activesupport", "5.0.7"
5
+ gem "activerecord", "6.1.0"
6
+ gem "activesupport", "6.1.0"
8
7
 
9
8
  gemspec path: "../"
@@ -7,10 +7,6 @@ module Delayed
7
7
  module JobGroups
8
8
  module Compatibility
9
9
 
10
- def self.mass_assignment_security_enabled?
11
- defined?(::ActiveRecord::MassAssignmentSecurity)
12
- end
13
-
14
10
  end
15
11
  end
16
12
  end
@@ -11,11 +11,7 @@ module Delayed
11
11
  end
12
12
 
13
13
  included do
14
- if Delayed::JobGroups::Compatibility.mass_assignment_security_enabled?
15
- attr_accessible :job_group_id, :blocked
16
- end
17
-
18
- belongs_to :job_group, class_name: 'Delayed::JobGroups::JobGroup'
14
+ belongs_to :job_group, class_name: 'Delayed::JobGroups::JobGroup', required: false
19
15
 
20
16
  class << self
21
17
  prepend ReadyToRunExtension
@@ -8,11 +8,6 @@ module Delayed
8
8
 
9
9
  self.table_name = "#{ActiveRecord::Base.table_name_prefix}delayed_job_groups"
10
10
 
11
- if Delayed::JobGroups::Compatibility.mass_assignment_security_enabled?
12
- attr_accessible :on_completion_job, :on_completion_job_options, :blocked, :on_cancellation_job,
13
- :on_cancellation_job_options, :failure_cancels_group
14
- end
15
-
16
11
  serialize :on_completion_job, Delayed::JobGroups::YamlLoader
17
12
  serialize :on_completion_job_options, Hash
18
13
  serialize :on_cancellation_job, Delayed::JobGroups::YamlLoader
@@ -30,6 +25,7 @@ module Delayed
30
25
  def mark_queueing_complete
31
26
  with_lock do
32
27
  raise 'JobGroup has already completed queueing' if queueing_complete?
28
+
33
29
  update_column(:queueing_complete, true)
34
30
  complete if ready_for_completion?
35
31
  end
@@ -66,13 +62,14 @@ module Delayed
66
62
  # zero will queue the job group's completion job and destroy the job group so
67
63
  # other jobs need to handle the job group having been destroyed already.
68
64
  job_group = where(id: job_group_id).lock(true).first
69
- job_group.send(:complete) if job_group && job_group.send(:ready_for_completion?)
65
+ job_group.send(:complete) if job_group&.send(:ready_for_completion?)
70
66
  end
71
67
  end
72
68
 
73
69
  def self.has_pending_jobs?(job_group_ids) # rubocop:disable Naming/PredicateName
74
70
  job_group_ids = Array(job_group_ids)
75
71
  return false if job_group_ids.empty?
72
+
76
73
  Delayed::Job.where(job_group_id: job_group_ids, failed_at: nil).exists?
77
74
  end
78
75
 
@@ -21,15 +21,14 @@ module Delayed
21
21
  # If a job in the job group fails, then cancel the whole job group.
22
22
  # Need to check that the job group is present since another
23
23
  # job may have concurrently cancelled it.
24
- if job.in_job_group? && job.job_group && job.job_group.failure_cancels_group?
25
- job.job_group.cancel
26
- end
24
+ job.job_group.cancel if job.in_job_group? && job.job_group&.failure_cancels_group?
27
25
  end
28
26
 
29
27
  lifecycle.after(:perform) do |_worker, job|
30
28
  # Make sure we only check to see if the job group is complete
31
- # if the job succeeded
32
- if job.in_job_group? && job_completed?(job)
29
+ # if the job succeeded or the job has failed (maxed out retries) with failure_cancels_group
30
+ # set to false
31
+ if job.in_job_group? && (job_completed?(job) || job_acceptably_failed?(job))
33
32
  JobGroup.check_for_completion(job.job_group_id)
34
33
  end
35
34
  end
@@ -44,6 +43,12 @@ module Delayed
44
43
  # if it has completed
45
44
  job.destroyed?
46
45
  end
46
+
47
+ def self.job_acceptably_failed?(job)
48
+ # Job has set failed_at (retries have maxed out) and failure_cancels_group is false signaling
49
+ # that the group should complete despite failures.
50
+ job.failed_at.present? && job.job_group.present? && !job.job_group.failure_cancels_group?
51
+ end
47
52
  end
48
53
  end
49
54
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Delayed
4
+ module JobGroups
5
+ class Railtie < ::Rails::Railtie
6
+ config.after_initialize do
7
+ Delayed::Backend::ActiveRecord::Job.include(Delayed::JobGroups::JobExtensions)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Delayed
4
4
  module JobGroups
5
- VERSION = '0.4.2'
5
+ VERSION = '0.7.0'
6
6
  end
7
7
  end
@@ -5,11 +5,13 @@ module Delayed
5
5
  module YamlLoader
6
6
  def self.load(yaml)
7
7
  return yaml unless yaml.is_a?(String) && /^---/.match(yaml)
8
+
8
9
  YAML.load_dj(yaml)
9
10
  end
10
11
 
11
12
  def self.dump(object)
12
13
  return if object.nil?
14
+
13
15
  YAML.dump(object)
14
16
  end
15
17
  end
@@ -11,6 +11,12 @@ require 'delayed/job_groups/plugin'
11
11
  require 'delayed/job_groups/yaml_loader'
12
12
  require 'delayed/job_groups/version'
13
13
 
14
- Delayed::Backend::ActiveRecord::Job.send(:include, Delayed::JobGroups::JobExtensions)
14
+ if defined?(Rails::Railtie)
15
+ # Postpone initialization to railtie for correct order
16
+ require 'delayed/job_groups/railtie'
17
+ else
18
+ # Do the same as in the railtie
19
+ Delayed::Backend::ActiveRecord::Job.include(Delayed::JobGroups::JobExtensions)
20
+ end
15
21
 
16
22
  Delayed::Worker.plugins << Delayed::JobGroups::Plugin
@@ -11,7 +11,7 @@ module DelayedJobGroupsPlugin
11
11
  source_paths << File.join(File.dirname(__FILE__), 'templates')
12
12
 
13
13
  def create_migration_file
14
- migration_template('migration.rb', 'db/migrate/create_delayed_job_groups.rb')
14
+ migration_template('migration.erb', 'db/migrate/create_delayed_job_groups.rb')
15
15
  end
16
16
 
17
17
  def self.next_migration_number(dirname)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class CreateDelayedJobGroups < ActiveRecord::Migration
3
+ class CreateDelayedJobGroups < ActiveRecord::Migration[<%= ActiveRecord::VERSION::MAJOR %>.<%= ActiveRecord::VERSION::MINOR %>]
4
4
 
5
5
  def up
6
6
  add_column(:delayed_jobs, :blocked, :boolean, default: false, null: false)
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe "delayed job extensions" do
4
+ it "provides an optional job_group_id" do
5
+ job_group = Delayed::JobGroups::JobGroup.create!
6
+ expect(Delayed::Job.new(job_group_id: job_group.id)).to be_valid
7
+ expect(Delayed::Job.new).to be_valid
8
+ end
9
+ end
@@ -50,6 +50,7 @@ describe Delayed::JobGroups::JobGroup do
50
50
  before { job_group.mark_queueing_complete }
51
51
 
52
52
  it { is_expected.to be_queueing_complete }
53
+
53
54
  it_behaves_like "the job group was completed"
54
55
  end
55
56
 
@@ -59,6 +60,7 @@ describe Delayed::JobGroups::JobGroup do
59
60
  before { job_group.mark_queueing_complete }
60
61
 
61
62
  it { is_expected.to be_queueing_complete }
63
+
62
64
  it_behaves_like "the job group was not completed"
63
65
  end
64
66
 
@@ -69,6 +71,7 @@ describe Delayed::JobGroups::JobGroup do
69
71
  end
70
72
 
71
73
  it { is_expected.to be_queueing_complete }
74
+
72
75
  it_behaves_like "the job group was not completed"
73
76
  end
74
77
  end
@@ -103,7 +106,7 @@ describe Delayed::JobGroups::JobGroup do
103
106
 
104
107
  context "when on failed jobs exist" do
105
108
  before do
106
- job.update_attributes!(failed_at: Time.now)
109
+ job.update!(failed_at: Time.now)
107
110
  Delayed::JobGroups::JobGroup.check_for_completion(job_group.id)
108
111
  end
109
112
 
@@ -199,6 +202,7 @@ describe Delayed::JobGroups::JobGroup do
199
202
  end
200
203
 
201
204
  its(:blocked?) { is_expected.to be(false) }
205
+
202
206
  it_behaves_like "the job group was completed"
203
207
  end
204
208
  end
@@ -229,7 +233,7 @@ describe Delayed::JobGroups::JobGroup do
229
233
  let(:failure_cancels_group) { true }
230
234
 
231
235
  before do
232
- job_group.update_attributes!(failure_cancels_group: failure_cancels_group)
236
+ job_group.update!(failure_cancels_group: failure_cancels_group)
233
237
  end
234
238
 
235
239
  context "when failures should cancel the group" do
@@ -5,56 +5,56 @@ describe Delayed::JobGroups::Plugin do
5
5
  @old_max_attempts = Delayed::Worker.max_attempts
6
6
  Delayed::Worker.max_attempts = 2
7
7
 
8
- CompletionJob.invoked = false
9
- CancellationJob.invoked = false
8
+ TestJobs::CompletionJob.invoked = false
9
+ TestJobs::CancellationJob.invoked = false
10
10
  end
11
11
 
12
12
  after do
13
13
  Delayed::Worker.max_attempts = @old_max_attempts
14
14
  end
15
15
 
16
- let!(:job_group) { Delayed::JobGroups::JobGroup.create!(on_completion_job: CompletionJob.new) }
16
+ let!(:job_group) { Delayed::JobGroups::JobGroup.create!(on_completion_job: TestJobs::CompletionJob.new) }
17
17
 
18
18
  it "runs the completion job after completing other jobs" do
19
- job_group.enqueue(NoOpJob.new)
20
- job_group.enqueue(NoOpJob.new)
19
+ job_group.enqueue(TestJobs::NoOpJob.new)
20
+ job_group.enqueue(TestJobs::NoOpJob.new)
21
21
  job_group.mark_queueing_complete
22
22
  expect(job_group_count).to eq 1
23
23
  expect(queued_job_count).to eq 2
24
24
 
25
25
  # Run our first job
26
26
  Delayed::Worker.new.work_off(1)
27
- expect(CompletionJob.invoked).to be(false)
27
+ expect(TestJobs::CompletionJob.invoked).to be(false)
28
28
  expect(job_group_count).to eq 1
29
29
  expect(queued_job_count).to eq 1
30
30
 
31
31
  # Run our second job which should enqueue the completion job
32
32
  Delayed::Worker.new.work_off(1)
33
- expect(CompletionJob.invoked).to be(false)
33
+ expect(TestJobs::CompletionJob.invoked).to be(false)
34
34
  expect(job_group_count).to eq 0
35
35
  expect(queued_job_count).to eq 1
36
36
 
37
37
  # Now we should run the completion job
38
38
  Delayed::Worker.new.work_off(1)
39
- expect(CompletionJob.invoked).to be(true)
39
+ expect(TestJobs::CompletionJob.invoked).to be(true)
40
40
  expect(queued_job_count).to eq 0
41
41
  end
42
42
 
43
43
  it "only runs the completion job after queueing is completed" do
44
- job_group.enqueue(NoOpJob.new)
45
- job_group.enqueue(NoOpJob.new)
44
+ job_group.enqueue(TestJobs::NoOpJob.new)
45
+ job_group.enqueue(TestJobs::NoOpJob.new)
46
46
  expect(job_group_count).to eq 1
47
47
  expect(queued_job_count).to eq 2
48
48
 
49
49
  # Run our first job
50
50
  Delayed::Worker.new.work_off(1)
51
- expect(CompletionJob.invoked).to be(false)
51
+ expect(TestJobs::CompletionJob.invoked).to be(false)
52
52
  expect(job_group_count).to eq 1
53
53
  expect(queued_job_count).to eq 1
54
54
 
55
55
  # Run our second job
56
56
  Delayed::Worker.new.work_off(1)
57
- expect(CompletionJob.invoked).to be(false)
57
+ expect(TestJobs::CompletionJob.invoked).to be(false)
58
58
  expect(job_group_count).to eq 1
59
59
  expect(queued_job_count).to eq 0
60
60
 
@@ -65,7 +65,7 @@ describe Delayed::JobGroups::Plugin do
65
65
 
66
66
  # Now we should run the completion job
67
67
  Delayed::Worker.new.work_off(1)
68
- expect(CompletionJob.invoked).to be(true)
68
+ expect(TestJobs::CompletionJob.invoked).to be(true)
69
69
  expect(queued_job_count).to eq 0
70
70
  end
71
71
 
@@ -75,15 +75,16 @@ describe Delayed::JobGroups::Plugin do
75
75
  it "cancels the group" do
76
76
  Delayed::Worker.max_attempts = 1
77
77
 
78
- job_group.enqueue(FailingJob.new)
79
- job_group.enqueue(NoOpJob.new)
78
+ job_group.enqueue(TestJobs::FailingJob.new)
79
+ job_group.enqueue(TestJobs::NoOpJob.new)
80
80
  job_group.mark_queueing_complete
81
81
  expect(queued_job_count).to eq 2
82
82
  expect(job_group_count).to eq 1
83
83
 
84
84
  # Run the job which should fail and cancel the JobGroup
85
85
  Delayed::Worker.new.work_off(1)
86
- expect(CompletionJob.invoked).to be(false)
86
+ # Completion job is not invoked
87
+ expect(TestJobs::CompletionJob.invoked).to be(false)
87
88
  expect(failed_job_count).to eq 1
88
89
  expect(queued_job_count).to eq 0
89
90
  expect(job_group_count).to eq 0
@@ -92,30 +93,83 @@ describe Delayed::JobGroups::Plugin do
92
93
 
93
94
  context "with failure_cancels_group disabled" do
94
95
 
95
- before { job_group.update_attributes!(failure_cancels_group: false) }
96
+ before { job_group.update!(failure_cancels_group: false) }
96
97
 
97
98
  it "does not cancel the group" do
98
99
  Delayed::Worker.max_attempts = 1
99
100
 
100
- job_group.enqueue(FailingJob.new)
101
- job_group.enqueue(NoOpJob.new)
101
+ job_group.enqueue(TestJobs::FailingJob.new)
102
+ job_group.enqueue(TestJobs::NoOpJob.new)
102
103
  job_group.mark_queueing_complete
103
104
  expect(queued_job_count).to eq 2
104
105
  expect(job_group_count).to eq 1
105
106
 
106
107
  # Run the job which should fail don't cancel the JobGroup
107
108
  Delayed::Worker.new.work_off(1)
108
- expect(CancellationJob.invoked).to be(false)
109
+ expect(TestJobs::CancellationJob.invoked).to be(false)
109
110
  expect(failed_job_count).to eq 1
110
111
  expect(queued_job_count).to eq 1
111
112
  expect(job_group_count).to eq 1
113
+
114
+ # Run the last job
115
+ Delayed::Worker.new.work_off(1)
116
+ expect(failed_job_count).to eq 1
117
+ expect(queued_job_count).to eq 1
118
+ expect(job_group_count).to eq 0
119
+
120
+ # Run the completion job
121
+ Delayed::Worker.new.work_off(1)
122
+ # Completion job is invoked
123
+ expect(TestJobs::CompletionJob.invoked).to be(true)
124
+ expect(failed_job_count).to eq 1
125
+ expect(queued_job_count).to eq 0
126
+ expect(job_group_count).to eq 0
127
+ end
128
+
129
+ it "runs completion job if last job failed" do
130
+ Delayed::Worker.max_attempts = 2
131
+
132
+ job_group.enqueue(TestJobs::NoOpJob.new)
133
+ job_group.enqueue(TestJobs::FailingJob.new)
134
+ job_group.mark_queueing_complete
135
+ expect(queued_job_count).to eq 2
136
+ expect(job_group_count).to eq 1
137
+
138
+ # Run the non failing job
139
+ Delayed::Worker.new.work_off(1)
140
+ expect(failed_job_count).to eq 0
141
+ expect(queued_job_count).to eq 1
142
+ expect(job_group_count).to eq 1
143
+
144
+ # Run the job which should error
145
+ Delayed::Worker.new.work_off(1)
146
+ # Completion job is not invoked
147
+ expect(TestJobs::CompletionJob.invoked).to be(false)
148
+ expect(failed_job_count).to eq 0
149
+ expect(queued_job_count).to eq 1
150
+ expect(job_group_count).to eq 1
151
+
152
+ # Run the job again which should fail
153
+ Timecop.travel(1.minute.from_now)
154
+ Delayed::Worker.new.work_off(1)
155
+ expect(failed_job_count).to eq 1
156
+ expect(queued_job_count).to eq 1
157
+ expect(job_group_count).to eq 0
158
+
159
+ # Run the completion job
160
+ Delayed::Worker.new.work_off(1)
161
+ # Completion job is invoked
162
+ expect(TestJobs::CompletionJob.invoked).to be(true)
163
+ expect(failed_job_count).to eq 1
164
+ expect(queued_job_count).to eq 0
165
+ expect(job_group_count).to eq 0
112
166
  end
113
167
  end
114
168
  end
115
169
 
116
170
  it "doesn't retry failed jobs if the job group has been canceled" do
117
171
  job_group.cancel
118
- Delayed::Job.enqueue(FailingJob.new, job_group_id: job_group.id)
172
+ Delayed::Job.enqueue(TestJobs::FailingJob.new, job_group_id: job_group.id)
119
173
  expect(queued_job_count).to eq 1
120
174
 
121
175
  # Run the job which should fail and should not queue a retry
@@ -128,8 +182,8 @@ describe Delayed::JobGroups::Plugin do
128
182
  job_group.blocked = true
129
183
  job_group.save!
130
184
 
131
- job_group.enqueue(NoOpJob.new)
132
- job_group.enqueue(NoOpJob.new)
185
+ job_group.enqueue(TestJobs::NoOpJob.new)
186
+ job_group.enqueue(TestJobs::NoOpJob.new)
133
187
  job_group.mark_queueing_complete
134
188
  expect(Delayed::Job.count).to eq 2
135
189
 
@@ -143,41 +197,41 @@ describe Delayed::JobGroups::Plugin do
143
197
 
144
198
  # Run our first job
145
199
  Delayed::Worker.new.work_off(1)
146
- expect(CompletionJob.invoked).to be(false)
200
+ expect(TestJobs::CompletionJob.invoked).to be(false)
147
201
  expect(job_group_count).to eq 1
148
202
  expect(Delayed::Job.count).to eq 1
149
203
 
150
204
  # Run our second job which should enqueue the completion job
151
205
  Delayed::Worker.new.work_off(1)
152
- expect(CompletionJob.invoked).to be(false)
206
+ expect(TestJobs::CompletionJob.invoked).to be(false)
153
207
  expect(job_group_count).to eq 0
154
208
  expect(Delayed::Job.count).to eq 1
155
209
 
156
210
  # Now we should run the completion job
157
211
  Delayed::Worker.new.work_off(1)
158
- expect(CompletionJob.invoked).to be(true)
212
+ expect(TestJobs::CompletionJob.invoked).to be(true)
159
213
  expect(Delayed::Job.count).to eq 0
160
214
  end
161
215
 
162
216
  context "when a cancellation job is provided" do
163
217
  let!(:job_group) do
164
- Delayed::JobGroups::JobGroup.create!(on_completion_job: CompletionJob.new,
165
- on_cancellation_job: CancellationJob.new)
218
+ Delayed::JobGroups::JobGroup.create!(on_completion_job: TestJobs::CompletionJob.new,
219
+ on_cancellation_job: TestJobs::CancellationJob.new)
166
220
  end
167
221
 
168
222
  it "runs the cancellation job after a job error causes cancellation" do
169
223
  Delayed::Worker.max_attempts = 1
170
224
 
171
- job_group.enqueue(FailingJob.new)
172
- job_group.enqueue(NoOpJob.new)
225
+ job_group.enqueue(TestJobs::FailingJob.new)
226
+ job_group.enqueue(TestJobs::NoOpJob.new)
173
227
  job_group.mark_queueing_complete
174
228
  expect(queued_job_count).to eq 2
175
229
  expect(job_group_count).to eq 1
176
230
 
177
231
  # Run the job which should fail and cancel the JobGroup
178
232
  Delayed::Worker.new.work_off(1)
179
- expect(CompletionJob.invoked).to be(false)
180
- expect(CancellationJob.invoked).to be(false)
233
+ expect(TestJobs::CompletionJob.invoked).to be(false)
234
+ expect(TestJobs::CancellationJob.invoked).to be(false)
181
235
  expect(failed_job_count).to eq 1
182
236
 
183
237
  expect(queued_job_count).to eq 1
@@ -185,24 +239,24 @@ describe Delayed::JobGroups::Plugin do
185
239
 
186
240
  # Now we should run the cancellation job
187
241
  Delayed::Worker.new.work_off(1)
188
- expect(CompletionJob.invoked).to be(false)
189
- expect(CancellationJob.invoked).to be(true)
242
+ expect(TestJobs::CompletionJob.invoked).to be(false)
243
+ expect(TestJobs::CancellationJob.invoked).to be(true)
190
244
  expect(queued_job_count).to eq 0
191
245
  end
192
246
 
193
247
  it "runs the cancellation job after the job group is cancelled" do
194
- job_group.enqueue(NoOpJob.new)
195
- job_group.enqueue(FailingJob.new)
248
+ job_group.enqueue(TestJobs::NoOpJob.new)
249
+ job_group.enqueue(TestJobs::FailingJob.new)
196
250
  job_group.mark_queueing_complete
197
251
  job_group.cancel
198
252
 
199
253
  # cancellation job should be queued
200
254
  expect(queued_job_count).to eq 1
201
- expect(CancellationJob.invoked).to be(false)
255
+ expect(TestJobs::CancellationJob.invoked).to be(false)
202
256
 
203
257
  # Run the cancellation job
204
258
  Delayed::Worker.new.work_off(1)
205
- expect(CancellationJob.invoked).to be(true)
259
+ expect(TestJobs::CancellationJob.invoked).to be(true)
206
260
  expect(queued_job_count).to eq 0
207
261
  end
208
262
  end
@@ -211,8 +265,8 @@ describe Delayed::JobGroups::Plugin do
211
265
  let!(:job_group) { Delayed::JobGroups::JobGroup.create! }
212
266
 
213
267
  it "doesn't queue a non-existent completion job" do
214
- job_group.enqueue(NoOpJob.new)
215
- job_group.enqueue(NoOpJob.new)
268
+ job_group.enqueue(TestJobs::NoOpJob.new)
269
+ job_group.enqueue(TestJobs::NoOpJob.new)
216
270
  job_group.mark_queueing_complete
217
271
  expect(job_group_count).to eq 1
218
272
  expect(queued_job_count).to eq 2
@@ -232,37 +286,6 @@ describe Delayed::JobGroups::Plugin do
232
286
  end
233
287
  end
234
288
 
235
- class FailingJob
236
-
237
- def perform
238
- raise 'Test failure'
239
- end
240
-
241
- end
242
-
243
- class NoOpJob
244
-
245
- def perform
246
-
247
- end
248
- end
249
-
250
- class CompletionJob
251
- cattr_accessor :invoked
252
-
253
- def perform
254
- CompletionJob.invoked = true
255
- end
256
- end
257
-
258
- class CancellationJob
259
- cattr_accessor :invoked
260
-
261
- def perform
262
- CancellationJob.invoked = true
263
- end
264
- end
265
-
266
289
  def job_group_count
267
290
  Delayed::JobGroups::JobGroup.count
268
291
  end
@@ -1,14 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  describe Delayed::JobGroups::YamlLoader do
4
- class Foo; end
5
-
6
4
  describe "#load" do
7
5
  context "with a correct yaml object representation" do
8
- let(:yaml) { '--- !ruby/object:Foo {}' }
6
+ let(:yaml) { '--- !ruby/object:TestJobs::Foo {}' }
9
7
 
10
8
  it "deserializes from YAML properly" do
11
- expect(Delayed::JobGroups::YamlLoader.load(yaml)).to be_a(Foo)
9
+ expect(Delayed::JobGroups::YamlLoader.load(yaml)).to be_a(TestJobs::Foo)
12
10
  end
13
11
  end
14
12
 
@@ -25,10 +23,10 @@ describe Delayed::JobGroups::YamlLoader do
25
23
 
26
24
  describe "#dump" do
27
25
  context "with an object" do
28
- let(:object) { Foo.new }
26
+ let(:object) { TestJobs::Foo.new }
29
27
 
30
28
  it "serializes into YAML properly" do
31
- expect(Delayed::JobGroups::YamlLoader.dump(object)).to eq("--- !ruby/object:Foo {}\n")
29
+ expect(Delayed::JobGroups::YamlLoader.dump(object)).to eq("--- !ruby/object:TestJobs::Foo {}\n")
32
30
  end
33
31
  end
34
32
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestJobs
4
+ class Foo; end
5
+
6
+ class FailingJob
7
+ def perform
8
+ raise 'Test failure'
9
+ end
10
+ end
11
+
12
+ class NoOpJob
13
+ def perform
14
+
15
+ end
16
+ end
17
+
18
+ class CompletionJob
19
+ cattr_accessor :invoked
20
+
21
+ def perform
22
+ CompletionJob.invoked = true
23
+ end
24
+ end
25
+
26
+ class CancellationJob
27
+ cattr_accessor :invoked
28
+
29
+ def perform
30
+ CancellationJob.invoked = true
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job_groups_plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Turkel
8
8
  - Randy Burkes
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-05-27 00:00:00.000000000 Z
12
+ date: 2021-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: delayed_job
@@ -59,34 +59,34 @@ dependencies:
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: '4.2'
62
+ version: '5.2'
63
63
  - - "<"
64
64
  - !ruby/object:Gem::Version
65
- version: '6.1'
65
+ version: '7'
66
66
  type: :runtime
67
67
  prerelease: false
68
68
  version_requirements: !ruby/object:Gem::Requirement
69
69
  requirements:
70
70
  - - ">="
71
71
  - !ruby/object:Gem::Version
72
- version: '4.2'
72
+ version: '5.2'
73
73
  - - "<"
74
74
  - !ruby/object:Gem::Version
75
- version: '6.1'
75
+ version: '7'
76
76
  - !ruby/object:Gem::Dependency
77
- name: coveralls
77
+ name: coveralls_reborn
78
78
  requirement: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '0'
82
+ version: 0.18.0
83
83
  type: :development
84
84
  prerelease: false
85
85
  version_requirements: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 0.18.0
90
90
  - !ruby/object:Gem::Dependency
91
91
  name: database_cleaner
92
92
  requirement: !ruby/object:Gem::Requirement
@@ -157,20 +157,34 @@ dependencies:
157
157
  - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
+ - !ruby/object:Gem::Dependency
161
+ name: rspec_junit_formatter
162
+ requirement: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ type: :development
168
+ prerelease: false
169
+ version_requirements: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
160
174
  - !ruby/object:Gem::Dependency
161
175
  name: salsify_rubocop
162
176
  requirement: !ruby/object:Gem::Requirement
163
177
  requirements:
164
- - - '='
178
+ - - "~>"
165
179
  - !ruby/object:Gem::Version
166
- version: 0.52.1.1
180
+ version: 1.0.1
167
181
  type: :development
168
182
  prerelease: false
169
183
  version_requirements: !ruby/object:Gem::Requirement
170
184
  requirements:
171
- - - '='
185
+ - - "~>"
172
186
  - !ruby/object:Gem::Version
173
- version: 0.52.1.1
187
+ version: 1.0.1
174
188
  - !ruby/object:Gem::Dependency
175
189
  name: simplecov
176
190
  requirement: !ruby/object:Gem::Requirement
@@ -222,10 +236,10 @@ executables: []
222
236
  extensions: []
223
237
  extra_rdoc_files: []
224
238
  files:
239
+ - ".circleci/config.yml"
225
240
  - ".gitignore"
226
241
  - ".rspec"
227
242
  - ".rubocop.yml"
228
- - ".travis.yml"
229
243
  - Appraisals
230
244
  - CHANGELOG.md
231
245
  - Gemfile
@@ -233,27 +247,28 @@ files:
233
247
  - README.md
234
248
  - Rakefile
235
249
  - delayed_job_groups.gemspec
236
- - gemfiles/rails_4.2.gemfile
237
- - gemfiles/rails_5.0.gemfile
238
- - gemfiles/rails_5.1.gemfile
239
250
  - gemfiles/rails_5.2.gemfile
240
251
  - gemfiles/rails_6.0.gemfile
252
+ - gemfiles/rails_6.1.gemfile
241
253
  - lib/delayed/job_groups/compatibility.rb
242
254
  - lib/delayed/job_groups/job_extensions.rb
243
255
  - lib/delayed/job_groups/job_group.rb
244
256
  - lib/delayed/job_groups/plugin.rb
257
+ - lib/delayed/job_groups/railtie.rb
245
258
  - lib/delayed/job_groups/version.rb
246
259
  - lib/delayed/job_groups/yaml_loader.rb
247
260
  - lib/delayed_job_groups_plugin.rb
248
261
  - lib/generators/delayed_job_groups_plugin/install_generator.rb
249
- - lib/generators/delayed_job_groups_plugin/templates/migration.rb
262
+ - lib/generators/delayed_job_groups_plugin/templates/migration.erb
250
263
  - spec/db/database.yml
251
264
  - spec/db/schema.rb
265
+ - spec/delayed/job_groups/job_extensions_spec.rb
252
266
  - spec/delayed/job_groups/job_group_spec.rb
253
267
  - spec/delayed/job_groups/plugin_spec.rb
254
268
  - spec/delayed/job_groups/yaml_loader_spec.rb
255
269
  - spec/spec_helper.rb
256
270
  - spec/support/destroyed_model.rb
271
+ - spec/support/test_jobs.rb
257
272
  homepage: https://github.com/salsify/delayed_job_groups_plugin
258
273
  licenses:
259
274
  - MIT
@@ -267,22 +282,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
267
282
  requirements:
268
283
  - - ">="
269
284
  - !ruby/object:Gem::Version
270
- version: '2.3'
285
+ version: '2.6'
271
286
  required_rubygems_version: !ruby/object:Gem::Requirement
272
287
  requirements:
273
288
  - - ">="
274
289
  - !ruby/object:Gem::Version
275
290
  version: '0'
276
291
  requirements: []
277
- rubygems_version: 3.0.8
278
- signing_key:
292
+ rubygems_version: 3.1.4
293
+ signing_key:
279
294
  specification_version: 4
280
295
  summary: Delayed::Job job groups plugin
281
296
  test_files:
282
297
  - spec/spec_helper.rb
283
298
  - spec/support/destroyed_model.rb
299
+ - spec/support/test_jobs.rb
284
300
  - spec/delayed/job_groups/plugin_spec.rb
285
301
  - spec/delayed/job_groups/job_group_spec.rb
286
302
  - spec/delayed/job_groups/yaml_loader_spec.rb
303
+ - spec/delayed/job_groups/job_extensions_spec.rb
287
304
  - spec/db/schema.rb
288
305
  - spec/db/database.yml
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- gemfile:
4
- - gemfiles/rails_4.2.gemfile
5
- - gemfiles/rails_5.0.gemfile
6
- - gemfiles/rails_5.1.gemfile
7
- - gemfiles/rails_5.2.gemfile
8
- - gemfiles/rails_6.0.gemfile
9
- rvm:
10
- - 2.3.8
11
- - 2.4.5
12
- - 2.5.3
13
- script:
14
- - bundle exec rspec
15
- - bundle exec rubocop
16
- matrix:
17
- exclude:
18
- - rvm: 2.3.8
19
- gemfile: gemfiles/rails_6.0.gemfile
20
- - rvm: 2.4.5
21
- gemfile: gemfiles/rails_6.0.gemfile
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "sqlite3", "~> 1.3.6"
6
- gem "activerecord", "4.2.10"
7
- gem "activesupport", "4.2.10"
8
-
9
- gemspec path: "../"
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "sqlite3", "~> 1.3.6"
6
- gem "activerecord", "5.1.6"
7
- gem "activesupport", "5.1.6"
8
-
9
- gemspec path: "../"