delayed_job_heartbeat_plugin 0.1.0 → 0.5.0

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