delayed_job_heartbeat_plugin 0.1.0 → 0.5.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.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +93 -0
  3. data/.github/CODEOWNERS +1 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +8 -0
  6. data/Appraisals +16 -0
  7. data/CHANGELOG.md +18 -0
  8. data/Gemfile +2 -0
  9. data/Rakefile +2 -0
  10. data/delayed_job_heartbeat_plugin.gemspec +22 -16
  11. data/gemfiles/rails_6.0.gemfile +8 -0
  12. data/gemfiles/rails_6.1.gemfile +8 -0
  13. data/gemfiles/rails_7.0.gemfile +8 -0
  14. data/lib/delayed/heartbeat/compatibility.rb +2 -0
  15. data/lib/delayed/heartbeat/configuration.rb +3 -1
  16. data/lib/delayed/heartbeat/delete_worker_results.rb +18 -26
  17. data/lib/delayed/heartbeat/plugin.rb +4 -5
  18. data/lib/delayed/heartbeat/railtie.rb +2 -0
  19. data/lib/delayed/heartbeat/tasks.rb +3 -1
  20. data/lib/delayed/heartbeat/version.rb +2 -2
  21. data/lib/delayed/heartbeat/worker.rb +3 -1
  22. data/lib/delayed/heartbeat/worker_heartbeat.rb +6 -3
  23. data/lib/delayed/heartbeat.rb +6 -6
  24. data/lib/delayed_job_heartbeat_plugin.rb +2 -0
  25. data/lib/generators/delayed_job_heartbeat_plugin/install_generator.rb +4 -2
  26. data/lib/generators/delayed_job_heartbeat_plugin/templates/{migration.rb → migration.erb} +1 -1
  27. data/spec/db/schema.rb +2 -0
  28. data/spec/delayed/heartbeat/delete_worker_results_spec.rb +13 -14
  29. data/spec/delayed/heartbeat/worker_heartbeat_spec.rb +2 -0
  30. data/spec/delayed/heartbeat_spec.rb +2 -2
  31. data/spec/spec_helper.rb +24 -12
  32. data/spec/support/destroyed_model.rb +2 -2
  33. data/spec/support/test_job.rb +2 -0
  34. data/spec/support/test_job_with_callbacks.rb +2 -0
  35. data/spec/support/wait.rb +2 -0
  36. metadata +111 -49
  37. data/.travis.yml +0 -14
  38. data/spec/db/database.yml +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d23c84e35c7097a52dd7c4ff8431ec634adc72b4
4
- data.tar.gz: 626b0561368160ea52dd2b7d4cf65240768cd3c7
2
+ SHA256:
3
+ metadata.gz: 5ba564b35f94921f30c324a5597705a743fd443946492b131f382282d2650c91
4
+ data.tar.gz: 63947153fbcf5b303d47981cee2a21eb8f4d76298ad6bc4e8fefe18da9cabe26
5
5
  SHA512:
6
- metadata.gz: fa8a6ff6c94fef094132d2625eb534a2f9b68730fae7696e57001ea513aa28ec7966bfff1b8c9f3e41ac10209ee817c3f495e5288aa4c445999def8c83fa2692
7
- data.tar.gz: 5a13041ce00bf26a2dfccd022831f32c1273587e701c9e759423519ae3bbaf4ffe35677bb11ff4c81f2d9bfc6e66114d37bb979d22c33d322a393e03a7b46156
6
+ metadata.gz: 25f9c2a073c041070f6f25d0b5c20a03fe60a598880a95f25478e62fca3d1c2cd046e312e4d7da4355254b86f3fc2b5551a8d35d287baff015dcde5a767dc727
7
+ data.tar.gz: 6abadd87e0918dc4f0cb9f501455444b8ea81e30473913d229967d95909682d1673402267fe47c20c4d134136e09592f6607648b70320fa1f6b508dc78e70bda
@@ -0,0 +1,93 @@
1
+ version: 2.1
2
+ jobs:
3
+ lint:
4
+ docker:
5
+ - image: salsify/ruby_ci:2.7.6
6
+ working_directory: ~/delayed_job_heartbeat_plugin
7
+ steps:
8
+ - checkout
9
+ - restore_cache:
10
+ keys:
11
+ - v1-gems-ruby-2.7.6-{{ checksum "delayed_job_heartbeat_plugin.gemspec" }}-{{ checksum "Gemfile" }}
12
+ - v1-gems-ruby-2.7.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.7.6-{{ checksum "delayed_job_heartbeat_plugin.gemspec" }}-{{ checksum "Gemfile" }}
22
+ paths:
23
+ - "vendor/bundle"
24
+ - "gemfiles/vendor/bundle"
25
+ - run:
26
+ name: Run Rubocop
27
+ command: bundle exec rubocop --config .rubocop.yml
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
+ DB_USER: "circleci"
38
+ - image: cimg/postgres:12.7
39
+ environment:
40
+ POSTGRES_USER: "circleci"
41
+ POSTGRES_DB: "circle_test"
42
+ POSTGRES_HOST_AUTH_METHOD: "trust"
43
+ environment:
44
+ RACK_ENV: "test"
45
+ RAILS_ENV: "test"
46
+ CIRCLE_TEST_REPORTS: "test-results"
47
+ BUNDLE_GEMFILE: << parameters.gemfile >>
48
+ working_directory: ~/delayed_job_heartbeat_plugin
49
+ steps:
50
+ - checkout
51
+ - restore_cache:
52
+ keys:
53
+ - v1-gems-ruby-<< parameters.ruby_version >>-{{ checksum "delayed_job_heartbeat_plugin.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
54
+ - v1-gems-ruby-<< parameters.ruby_version >>-
55
+ - run:
56
+ name: Install Gems
57
+ command: |
58
+ if ! bundle check --path=vendor/bundle; then
59
+ bundle install --path=vendor/bundle --jobs=4 --retry=3
60
+ bundle clean
61
+ fi
62
+ - save_cache:
63
+ key: v1-gems-ruby-<< parameters.ruby_version >>-{{ checksum "delayed_job_heartbeat_plugin.gemspec" }}-{{ checksum "<< parameters.gemfile >>" }}
64
+ paths:
65
+ - "vendor/bundle"
66
+ - "gemfiles/vendor/bundle"
67
+ - run:
68
+ name: Wait for Database
69
+ command: dockerize -wait tcp://localhost:5432 -timeout 60s
70
+ - run:
71
+ name: Wait for Database User
72
+ command: t=30; for i in `seq $t`; do psql -h localhost -p 5432 -U circleci -d circle_test -c '\q' && break; [ $i -eq $t ] && return 2; sleep 1; done;
73
+ - run:
74
+ name: Run Tests
75
+ command: |
76
+ bundle exec rspec --format RspecJunitFormatter --out $CIRCLE_TEST_REPORTS/rspec/junit.xml --format progress spec
77
+ - store_test_results:
78
+ path: "test-results"
79
+ workflows:
80
+ build:
81
+ jobs:
82
+ - lint
83
+ - test:
84
+ matrix:
85
+ parameters:
86
+ gemfile:
87
+ - "gemfiles/rails_6.0.gemfile"
88
+ - "gemfiles/rails_6.1.gemfile"
89
+ - "gemfiles/rails_7.0.gemfile"
90
+ ruby_version:
91
+ - "2.7.6"
92
+ - "3.0.4"
93
+ - "3.1.2"
@@ -0,0 +1 @@
1
+ * @jturkel @will89
data/.gitignore CHANGED
@@ -7,3 +7,6 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ log/
11
+ gemfiles/*.gemfile.lock
12
+ gemfiles/.bundle
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ inherit_gem:
2
+ salsify_rubocop: conf/rubocop.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.7
6
+ Exclude:
7
+ - 'vendor/**/*'
8
+ - 'gemfiles/**/*'
data/Appraisals ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise 'rails-6.0' do
4
+ gem 'activerecord', '~> 6.0.4'
5
+ gem 'activesupport', '~> 6.0.4'
6
+ end
7
+
8
+ appraise 'rails-6.1' do
9
+ gem 'activerecord', '~> 6.1.5'
10
+ gem 'activesupport', '~> 6.1.5'
11
+ end
12
+
13
+ appraise 'rails-7.0' do
14
+ gem 'activerecord', '~> 7.0.2'
15
+ gem 'activesupport', '~> 7.0.2'
16
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ ### 0.5.0
4
+ - Drop support for ruby < 2.7
5
+ - Add support for ruby 3.1
6
+ - Drop Rails 5.2
7
+ - Add Rails 7.0
8
+
9
+ ### 0.4.0
10
+ - Use frozen string literals.
11
+
12
+ ### 0.3.0
13
+ * Drop support for Ruby < 2.5.
14
+ * Drop support for Rails < 5.2.
15
+ * Bugfix for rails version in generated migration files
16
+
17
+ ### 0.2.0
18
+ * Enable correlation between workers and unlocked jobs in results returned from deleting workers
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in delayed_job_heartbeat_plugin.gemspec
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
@@ -1,5 +1,6 @@
1
- # encoding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'delayed/heartbeat/version'
5
6
 
@@ -13,27 +14,32 @@ Gem::Specification.new do |spec|
13
14
  spec.homepage = 'https://github.com/salsify/delayed_job_heartbeat_plugin'
14
15
  spec.license = 'MIT'
15
16
 
16
- spec.files = `git ls-files`.split($/)
17
+ if spec.respond_to?(:metadata)
18
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
19
+ spec.metadata['rubygems_mfa_required'] = 'true'
20
+ else
21
+ raise 'RubyGems 2.0 or newer is required to set allowed_push_host.'
22
+ end
23
+
24
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
17
25
  spec.test_files = Dir.glob('spec/**/*')
18
26
  spec.require_paths = ['lib']
19
27
 
20
- spec.required_ruby_version = '>= 2.0'
28
+ spec.required_ruby_version = '>= 2.7'
21
29
 
22
30
  spec.add_dependency 'delayed_job', '>= 4.1.0'
23
31
  spec.add_dependency 'delayed_job_active_record', '>= 4.1.0'
24
32
 
25
- spec.add_development_dependency 'activerecord', ENV.fetch('RAILS_VERSION', ['>= 3.2', '< 4.3'])
26
- spec.add_development_dependency 'coveralls'
33
+ spec.add_development_dependency 'activerecord', ['>= 5.2', '< 7.1']
34
+ spec.add_development_dependency 'appraisal'
35
+ spec.add_development_dependency 'bundler'
36
+ spec.add_development_dependency 'coveralls_reborn', '>= 0.18.0'
27
37
  spec.add_development_dependency 'database_cleaner', '>= 1.2'
28
- spec.add_development_dependency 'rake'
29
- spec.add_development_dependency 'rspec', '3.3.0'
30
- spec.add_development_dependency 'simplecov', '~> 0.7.1'
38
+ spec.add_development_dependency 'pg'
39
+ spec.add_development_dependency 'rake', '~> 13.0'
40
+ spec.add_development_dependency 'rspec', '~> 3'
41
+ spec.add_development_dependency 'rspec_junit_formatter'
42
+ spec.add_development_dependency 'salsify_rubocop', '~> 1.0.2'
43
+ spec.add_development_dependency 'simplecov'
31
44
  spec.add_development_dependency 'timecop'
32
-
33
- if RUBY_PLATFORM == 'java'
34
- spec.add_development_dependency 'jdbc-sqlite3'
35
- spec.add_development_dependency 'activerecord-jdbcsqlite3-adapter'
36
- else
37
- spec.add_development_dependency 'sqlite3'
38
- end
39
45
  end
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.0.4"
6
+ gem "activesupport", "~> 6.0.4"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.1.5"
6
+ gem "activesupport", "~> 6.1.5"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 7.0.2"
6
+ gem "activesupport", "~> 7.0.2"
7
+
8
+ gemspec path: "../"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/version'
2
4
  require 'active_record/version'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delayed
2
4
  module Heartbeat
3
5
  class Configuration
@@ -22,7 +24,7 @@ module Delayed
22
24
 
23
25
  self.heartbeat_timeout_seconds ||= 180
24
26
  self.heartbeat_interval_seconds ||= 60
25
- self.on_worker_termination ||= Proc.new { }
27
+ self.on_worker_termination ||= Proc.new {}
26
28
  end
27
29
  end
28
30
  end
@@ -1,42 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delayed
2
4
  module Heartbeat
3
5
  class DeleteWorkerResults
4
- attr_reader :workers, :unlocked_jobs
6
+ def initialize(worker_job_map)
7
+ @worker_job_map = worker_job_map
8
+ end
9
+
10
+ def workers
11
+ @worker_job_map.keys
12
+ end
5
13
 
6
- def initialize(workers, unlocked_jobs)
7
- @workers = workers
8
- @unlocked_jobs = unlocked_jobs
14
+ def unlocked_jobs(worker = nil)
15
+ worker ? @worker_job_map.fetch(worker, []) : @worker_job_map.values.flatten
9
16
  end
10
17
 
11
18
  def empty?
12
- workers.empty? && unlocked_jobs.empty?
19
+ @worker_job_map.empty?
13
20
  end
14
21
 
15
22
  def to_s
16
23
  io = StringIO.new
17
24
  workers.each do |worker|
18
- io.puts("Deleted worker #{worker_description(worker)}")
25
+ worker_description = "#{worker.label}(#{worker.name})"
26
+ io.puts("Deleted worker #{worker_description}")
27
+ unlocked_jobs(worker).each do |unlocked_job|
28
+ io.puts("Unlocked orphaned job #{unlocked_job.id} from worker #{worker_description}")
29
+ end
19
30
  end
20
-
21
- unlocked_jobs.each do |unlocked_job|
22
- worker = worker_map[unlocked_job.locked_by]
23
- worker_string = worker ? worker_description(worker) : unlocked_job.locked_by
24
- io.puts("Unlocked orphaned job #{unlocked_job.id} from worker #{worker_string}")
25
- end
26
-
27
- io.string
28
- end
29
-
30
- private
31
-
32
- def worker_map
33
- @worker_map ||= workers.each_with_object(Hash.new) do |worker, worker_map|
34
- worker_map[worker.name] = worker
35
- end
36
- end
37
-
38
- def worker_description(worker)
39
- "#{worker.label}(#{worker.name})"
31
+ io.string.rstrip
40
32
  end
41
33
  end
42
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
2
4
 
3
5
  module Delayed
@@ -6,12 +8,10 @@ module Delayed
6
8
 
7
9
  callbacks do |lifecycle|
8
10
  lifecycle.before(:execute) do |worker|
9
- if Delayed::Heartbeat.configuration.enabled?
10
- @heartbeat = Delayed::Heartbeat::WorkerHeartbeat.new(worker.name)
11
- end
11
+ @heartbeat = Delayed::Heartbeat::WorkerHeartbeat.new(worker.name) if Delayed::Heartbeat.configuration.enabled?
12
12
  end
13
13
 
14
- lifecycle.after(:execute) do |worker|
14
+ lifecycle.after(:execute) do |_worker|
15
15
  @heartbeat.stop if @heartbeat
16
16
  end
17
17
  end
@@ -19,4 +19,3 @@ module Delayed
19
19
  end
20
20
  end
21
21
  end
22
-
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delayed_job'
2
4
  require 'rails'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  namespace :delayed do
2
4
  namespace :heartbeat do
3
5
  desc 'Cleans up workers that have not heartbeated recently.'
@@ -18,7 +20,7 @@ namespace :delayed do
18
20
  end
19
21
 
20
22
  def verbose?
21
- ENV['VERBOSE'].to_s.downcase == 'true'
23
+ ENV['VERBOSE'].to_s.casecmp('true').zero?
22
24
  end
23
25
  end
24
26
  end
@@ -1,7 +1,7 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Delayed
4
4
  module Heartbeat
5
- VERSION = '0.1.0'.freeze
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delayed/heartbeat/compatibility'
2
4
 
3
5
  module Delayed
@@ -43,7 +45,7 @@ module Delayed
43
45
  end
44
46
 
45
47
  def self.workers_with_different_version(current_version)
46
- where('version != ?', current_version)
48
+ where('version != ?', current_version)
47
49
  end
48
50
 
49
51
  def self.delete_workers(workers)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delayed
2
4
  module Heartbeat
3
5
  class WorkerHeartbeat
@@ -40,12 +42,13 @@ module Delayed
40
42
  def run_heartbeat_loop
41
43
  loop do
42
44
  break if sleep_interruptibly(heartbeat_interval)
45
+
43
46
  update_heartbeat
44
47
  # Return the connection back to the pool since we won't be needing
45
48
  # it again for a while.
46
49
  Delayed::Backend::ActiveRecord::Job.clear_active_connections!
47
50
  end
48
- rescue => e
51
+ rescue StandardError => e
49
52
  # We don't want the worker to continue running if the heartbeat can't be written.
50
53
  # Don't use Thread.abort_on_exception because that will give Delayed::Job a chance
51
54
  # to mark the job as failed which will unlock it even though the clock
@@ -65,8 +68,8 @@ module Delayed
65
68
  if heartbeat_delta_seconds < heartbeat_timeout_seconds || self_termination_disabled?
66
69
  @worker_model.update_column(:last_heartbeat_at, now)
67
70
  else
68
- raise Timeout::Error, "Worker heartbeat not updated for #{heartbeat_delta_seconds} seconds which " \
69
- "exceeds timeout\n. Current job: #{ @worker_model.job.inspect}"
71
+ raise Timeout::Error.new("Worker heartbeat not updated for #{heartbeat_delta_seconds} seconds which " \
72
+ "exceeds timeout\n. Current job: #{@worker_model.job.inspect}")
70
73
  end
71
74
  end
72
75
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delayed/heartbeat/compatibility'
2
4
  require 'delayed/heartbeat/configuration'
3
5
  require 'delayed/heartbeat/delete_worker_results'
@@ -16,9 +18,7 @@ module Delayed
16
18
  yield(configuration) if block_given?
17
19
  end
18
20
 
19
- def configuration
20
- @configuration
21
- end
21
+ attr_reader :configuration
22
22
 
23
23
  def delete_workers_with_different_version(current_version = configuration.worker_version)
24
24
  old_workers = Delayed::Heartbeat::Worker.workers_with_different_version(current_version)
@@ -34,11 +34,11 @@ module Delayed
34
34
 
35
35
  def cleanup_workers(workers, mark_attempt_failed: true)
36
36
  Delayed::Heartbeat::Worker.transaction do
37
- orphaned_jobs = workers.flat_map do |worker|
38
- worker.unlock_jobs(mark_attempt_failed: mark_attempt_failed)
37
+ worker_job_map = workers.each_with_object(Hash.new) do |worker, result|
38
+ result[worker] = worker.unlock_jobs(mark_attempt_failed: mark_attempt_failed)
39
39
  end
40
40
  Delayed::Heartbeat::Worker.delete_workers(workers)
41
- Delayed::Heartbeat::DeleteWorkerResults.new(workers, orphaned_jobs)
41
+ Delayed::Heartbeat::DeleteWorkerResults.new(worker_job_map)
42
42
  end
43
43
  end
44
44
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'active_record'
3
5
  require 'delayed_job'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails/generators'
2
4
  require 'rails/generators/migration'
3
5
  require 'rails/generators/active_record'
@@ -6,10 +8,10 @@ module DelayedJobHeartbeatPlugin
6
8
  class InstallGenerator < Rails::Generators::Base
7
9
  include Rails::Generators::Migration
8
10
 
9
- self.source_paths << File.join(File.dirname(__FILE__), 'templates')
11
+ source_paths << File.join(File.dirname(__FILE__), 'templates')
10
12
 
11
13
  def create_migration_file
12
- migration_template('migration.rb', 'db/migrate/create_delayed_workers.rb')
14
+ migration_template('migration.erb', 'db/migrate/create_delayed_workers.rb')
13
15
  end
14
16
 
15
17
  def self.next_migration_number(dirname)
@@ -1,4 +1,4 @@
1
- class CreateDelayedWorkers < ActiveRecord::Migration
1
+ class CreateDelayedWorkers < ActiveRecord::Migration[<%= ActiveRecord::VERSION::MAJOR %>.<%= ActiveRecord::VERSION::MINOR %>]
2
2
 
3
3
  def change
4
4
  create_table(:delayed_workers) do |t|
data/spec/db/schema.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ActiveRecord::Schema.define(version: 0) do
2
4
 
3
5
  create_table(:delayed_jobs, force: true) do |t|
@@ -1,34 +1,33 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Delayed::Heartbeat::DeleteWorkerResults do
4
6
  let(:worker) { create_worker(name: 'my-worker') }
5
7
  let(:job) { create_job(locked_by: worker.name) }
6
- let(:results) { create_results([worker], [job]) }
8
+ let(:results) { create_results(worker => [job]) }
7
9
 
8
10
  describe "#workers" do
9
11
  specify { expect(results.workers).to eq [worker] }
10
12
  end
11
13
 
12
14
  describe "#unlocked_jobs" do
13
- specify { expect(results.unlocked_jobs).to eq [job] }
15
+ let(:other_worker) { create_worker(name: 'my-other-worker') }
16
+ let(:other_job) { create_job(locked_by: worker.name) }
17
+ let(:results) { create_results(worker => [job], other_worker => [other_job]) }
18
+
19
+ specify { expect(results.unlocked_jobs(worker)).to eq [job] }
20
+ specify { expect(results.unlocked_jobs).to match_array [job, other_job] }
14
21
  end
15
22
 
16
23
  describe "#to_s" do
17
24
  it "includes workers" do
18
- results = create_results([worker], [])
25
+ results = create_results(worker => [])
19
26
  expect(results.to_s).to include(worker.name)
20
27
  end
21
28
 
22
- it "includes jobs for known workers" do
23
- results = create_results([worker], [job])
24
- expect(results.to_s).to include(job.id.to_s)
25
- end
26
-
27
- it "includes jobs locked by an unknown worker" do
28
- job = create_job(locked_by: 'unknown-worker')
29
- results = create_results([], [job])
29
+ it "includes jobs for workers" do
30
30
  expect(results.to_s).to include(job.id.to_s)
31
- expect(results.to_s).to include(job.locked_by)
32
31
  end
33
32
  end
34
33
 
@@ -41,7 +40,7 @@ describe Delayed::Heartbeat::DeleteWorkerResults do
41
40
  Delayed::Job.create!(attributes)
42
41
  end
43
42
 
44
- def create_results(workers, unlocked_jobs)
45
- Delayed::Heartbeat::DeleteWorkerResults.new(workers, unlocked_jobs)
43
+ def create_results(worker_job_map)
44
+ Delayed::Heartbeat::DeleteWorkerResults.new(worker_job_map)
46
45
  end
47
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Delayed::Heartbeat::WorkerHeartbeat, cleaner_strategy: :truncation do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Delayed::Heartbeat do
@@ -78,5 +80,3 @@ describe Delayed::Heartbeat do
78
80
  end
79
81
 
80
82
  end
81
-
82
-
data/spec/spec_helper.rb CHANGED
@@ -1,12 +1,13 @@
1
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __dir__)
2
4
 
3
5
  require 'simplecov'
4
6
  require 'coveralls'
5
7
 
6
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
7
- SimpleCov::Formatter::HTMLFormatter,
8
- Coveralls::SimpleCov::Formatter
9
- ]
8
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
9
+ [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
10
+ )
10
11
  SimpleCov.start do
11
12
  add_filter 'spec'
12
13
  end
@@ -30,27 +31,38 @@ Delayed::Worker.logger.level = Logger::DEBUG
30
31
  ActiveRecord::Base.logger = Delayed::Worker.logger
31
32
  ActiveRecord::Migration.verbose = false
32
33
 
33
- db_adapter = ENV.fetch('ADAPTER', 'sqlite3')
34
- config = YAML.load(File.read('spec/db/database.yml'))
35
- ActiveRecord::Base.establish_connection(config[db_adapter])
36
- require 'db/schema'
34
+ database_name = 'delayed_job_heartbeat_plugin_test'
35
+ database_host = ENV.fetch('PGHOST', 'localhost')
36
+ database_port = ENV.fetch('PGPORT', 5432)
37
37
 
38
38
  RSpec.configure do |config|
39
39
  config.order = 'random'
40
40
 
41
41
  config.before(:suite) do
42
+ db_connection_args = "--host #{database_host} --port #{database_port}"
43
+ `dropdb #{db_connection_args} --if-exists #{database_name} 2> /dev/null`
44
+ `createdb #{db_connection_args} #{database_name}`
45
+
46
+ pg_version = `psql #{db_connection_args} --dbname #{database_name} --tuples-only --command "select version()";`
47
+ puts "Testing with Postgres version: #{pg_version.strip}"
48
+ puts "Testing with ActiveRecord #{ActiveRecord::VERSION::STRING}"
49
+
50
+ database_url = "postgres://#{database_host}:#{database_port}/#{database_name}"
51
+ puts "Using database #{database_url}"
52
+ ActiveRecord::Base.establish_connection(database_url)
53
+ require 'db/schema'
42
54
  DatabaseCleaner.clean_with(:truncation)
43
55
  end
44
56
 
45
- config.before(:each) do |example|
57
+ config.before do |example|
46
58
  DatabaseCleaner.strategy = example.metadata.fetch(:cleaner_strategy, :transaction)
47
59
  end
48
60
 
49
- config.before(:each) do
61
+ config.before do
50
62
  DatabaseCleaner.start
51
63
  end
52
64
 
53
- config.after(:each) do
65
+ config.after do
54
66
  DatabaseCleaner.clean
55
67
  end
56
68
  end
@@ -1,4 +1,4 @@
1
- # encoding: UTF-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  RSpec::Matchers.define :have_been_destroyed do
4
4
  match do |actual|
@@ -6,7 +6,7 @@ RSpec::Matchers.define :have_been_destroyed do
6
6
  end
7
7
 
8
8
  description do
9
- "model should have been destroyed"
9
+ 'model should have been destroyed'
10
10
  end
11
11
 
12
12
  failure_message do |actual|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class TestJob
2
4
  def perform
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class TestJobWithCallbacks
2
4
  cattr_accessor :called_callbacks
3
5
  self.called_callbacks = []
data/spec/support/wait.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Wait
2
4
  def self.for(condition_name, max_wait_time: 5, polling_interval: 0.001)
3
5
  wait_until = Time.now + max_wait_time.seconds
metadata CHANGED
@@ -1,159 +1,215 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job_heartbeat_plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Turkel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-06 00:00:00.000000000 Z
11
+ date: 2022-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: delayed_job
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 4.1.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 4.1.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: delayed_job_active_record
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 4.1.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 4.1.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: activerecord
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '3.2'
48
- - - <
47
+ version: '5.2'
48
+ - - "<"
49
49
  - !ruby/object:Gem::Version
50
- version: '4.3'
50
+ version: '7.1'
51
51
  type: :development
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - '>='
55
+ - - ">="
56
56
  - !ruby/object:Gem::Version
57
- version: '3.2'
58
- - - <
57
+ version: '5.2'
58
+ - - "<"
59
59
  - !ruby/object:Gem::Version
60
- version: '4.3'
60
+ version: '7.1'
61
61
  - !ruby/object:Gem::Dependency
62
- name: coveralls
62
+ name: appraisal
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - '>='
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - '>='
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: bundler
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: coveralls_reborn
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 0.18.0
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 0.18.0
75
103
  - !ruby/object:Gem::Dependency
76
104
  name: database_cleaner
77
105
  requirement: !ruby/object:Gem::Requirement
78
106
  requirements:
79
- - - '>='
107
+ - - ">="
80
108
  - !ruby/object:Gem::Version
81
109
  version: '1.2'
82
110
  type: :development
83
111
  prerelease: false
84
112
  version_requirements: !ruby/object:Gem::Requirement
85
113
  requirements:
86
- - - '>='
114
+ - - ">="
87
115
  - !ruby/object:Gem::Version
88
116
  version: '1.2'
89
117
  - !ruby/object:Gem::Dependency
90
- name: rake
118
+ name: pg
91
119
  requirement: !ruby/object:Gem::Requirement
92
120
  requirements:
93
- - - '>='
121
+ - - ">="
94
122
  - !ruby/object:Gem::Version
95
123
  version: '0'
96
124
  type: :development
97
125
  prerelease: false
98
126
  version_requirements: !ruby/object:Gem::Requirement
99
127
  requirements:
100
- - - '>='
128
+ - - ">="
101
129
  - !ruby/object:Gem::Version
102
130
  version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: rake
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '13.0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '13.0'
103
145
  - !ruby/object:Gem::Dependency
104
146
  name: rspec
105
147
  requirement: !ruby/object:Gem::Requirement
106
148
  requirements:
107
- - - '='
149
+ - - "~>"
108
150
  - !ruby/object:Gem::Version
109
- version: 3.3.0
151
+ version: '3'
110
152
  type: :development
111
153
  prerelease: false
112
154
  version_requirements: !ruby/object:Gem::Requirement
113
155
  requirements:
114
- - - '='
156
+ - - "~>"
115
157
  - !ruby/object:Gem::Version
116
- version: 3.3.0
158
+ version: '3'
117
159
  - !ruby/object:Gem::Dependency
118
- name: simplecov
160
+ name: rspec_junit_formatter
119
161
  requirement: !ruby/object:Gem::Requirement
120
162
  requirements:
121
- - - ~>
163
+ - - ">="
122
164
  - !ruby/object:Gem::Version
123
- version: 0.7.1
165
+ version: '0'
124
166
  type: :development
125
167
  prerelease: false
126
168
  version_requirements: !ruby/object:Gem::Requirement
127
169
  requirements:
128
- - - ~>
170
+ - - ">="
129
171
  - !ruby/object:Gem::Version
130
- version: 0.7.1
172
+ version: '0'
131
173
  - !ruby/object:Gem::Dependency
132
- name: timecop
174
+ name: salsify_rubocop
133
175
  requirement: !ruby/object:Gem::Requirement
134
176
  requirements:
135
- - - '>='
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: 1.0.2
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - "~>"
185
+ - !ruby/object:Gem::Version
186
+ version: 1.0.2
187
+ - !ruby/object:Gem::Dependency
188
+ name: simplecov
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
136
192
  - !ruby/object:Gem::Version
137
193
  version: '0'
138
194
  type: :development
139
195
  prerelease: false
140
196
  version_requirements: !ruby/object:Gem::Requirement
141
197
  requirements:
142
- - - '>='
198
+ - - ">="
143
199
  - !ruby/object:Gem::Version
144
200
  version: '0'
145
201
  - !ruby/object:Gem::Dependency
146
- name: sqlite3
202
+ name: timecop
147
203
  requirement: !ruby/object:Gem::Requirement
148
204
  requirements:
149
- - - '>='
205
+ - - ">="
150
206
  - !ruby/object:Gem::Version
151
207
  version: '0'
152
208
  type: :development
153
209
  prerelease: false
154
210
  version_requirements: !ruby/object:Gem::Requirement
155
211
  requirements:
156
- - - '>='
212
+ - - ">="
157
213
  - !ruby/object:Gem::Version
158
214
  version: '0'
159
215
  description:
@@ -163,15 +219,22 @@ executables: []
163
219
  extensions: []
164
220
  extra_rdoc_files: []
165
221
  files:
166
- - .gitignore
167
- - .rspec
168
- - .travis.yml
222
+ - ".circleci/config.yml"
223
+ - ".github/CODEOWNERS"
224
+ - ".gitignore"
225
+ - ".rspec"
226
+ - ".rubocop.yml"
227
+ - Appraisals
228
+ - CHANGELOG.md
169
229
  - Gemfile
170
230
  - LICENSE.txt
171
231
  - README.md
172
232
  - Rakefile
173
233
  - bin/setup
174
234
  - delayed_job_heartbeat_plugin.gemspec
235
+ - gemfiles/rails_6.0.gemfile
236
+ - gemfiles/rails_6.1.gemfile
237
+ - gemfiles/rails_7.0.gemfile
175
238
  - lib/delayed/heartbeat.rb
176
239
  - lib/delayed/heartbeat/compatibility.rb
177
240
  - lib/delayed/heartbeat/configuration.rb
@@ -184,8 +247,7 @@ files:
184
247
  - lib/delayed/heartbeat/worker_heartbeat.rb
185
248
  - lib/delayed_job_heartbeat_plugin.rb
186
249
  - lib/generators/delayed_job_heartbeat_plugin/install_generator.rb
187
- - lib/generators/delayed_job_heartbeat_plugin/templates/migration.rb
188
- - spec/db/database.yml
250
+ - lib/generators/delayed_job_heartbeat_plugin/templates/migration.erb
189
251
  - spec/db/schema.rb
190
252
  - spec/delayed/heartbeat/delete_worker_results_spec.rb
191
253
  - spec/delayed/heartbeat/worker_heartbeat_spec.rb
@@ -198,29 +260,29 @@ files:
198
260
  homepage: https://github.com/salsify/delayed_job_heartbeat_plugin
199
261
  licenses:
200
262
  - MIT
201
- metadata: {}
263
+ metadata:
264
+ allowed_push_host: https://rubygems.org
265
+ rubygems_mfa_required: 'true'
202
266
  post_install_message:
203
267
  rdoc_options: []
204
268
  require_paths:
205
269
  - lib
206
270
  required_ruby_version: !ruby/object:Gem::Requirement
207
271
  requirements:
208
- - - '>='
272
+ - - ">="
209
273
  - !ruby/object:Gem::Version
210
- version: '2.0'
274
+ version: '2.7'
211
275
  required_rubygems_version: !ruby/object:Gem::Requirement
212
276
  requirements:
213
- - - '>='
277
+ - - ">="
214
278
  - !ruby/object:Gem::Version
215
279
  version: '0'
216
280
  requirements: []
217
- rubyforge_project:
218
- rubygems_version: 2.2.2
281
+ rubygems_version: 3.2.33
219
282
  signing_key:
220
283
  specification_version: 4
221
284
  summary: Delayed::Job plugin to unlock jobs from dead workers
222
285
  test_files:
223
- - spec/db/database.yml
224
286
  - spec/db/schema.rb
225
287
  - spec/delayed/heartbeat/delete_worker_results_spec.rb
226
288
  - spec/delayed/heartbeat/worker_heartbeat_spec.rb
data/.travis.yml DELETED
@@ -1,14 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- before_install: gem install bundler -v 1.10.6
4
- env:
5
- matrix:
6
- - RAILS_VERSION="~> 3.2.22"
7
- - RAILS_VERSION="~> 4.0.13"
8
- - RAILS_VERSION="~> 4.1.13"
9
- - RAILS_VERSION="~> 4.2.4"
10
- rvm:
11
- - 2.0.0
12
- - 2.1.7
13
- - 2.2.3
14
-
data/spec/db/database.yml DELETED
@@ -1,5 +0,0 @@
1
- sqlite3:
2
- adapter: sqlite3
3
- pool: 5
4
- timeout: 15000
5
- database: tmp/sqlite3.db