delayed_job_groups_plugin 0.4.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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: "../"