inst-jobs 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/db/migrate/20101216224513_create_delayed_jobs.rb +9 -7
- data/db/migrate/20110531144916_cleanup_delayed_jobs_indexes.rb +8 -13
- data/db/migrate/20110610213249_optimize_delayed_jobs.rb +8 -8
- data/db/migrate/20110831210257_add_delayed_jobs_next_in_strand.rb +25 -25
- data/db/migrate/20120510004759_delayed_jobs_delete_trigger_lock_for_update.rb +4 -8
- data/db/migrate/20120531150712_drop_psql_jobs_pop_fn.rb +1 -3
- data/db/migrate/20120607164022_delayed_jobs_use_advisory_locks.rb +11 -15
- data/db/migrate/20120607181141_index_jobs_on_locked_by.rb +1 -1
- data/db/migrate/20120608191051_add_jobs_run_at_index.rb +2 -2
- data/db/migrate/20120927184213_change_delayed_jobs_handler_to_text.rb +1 -1
- data/db/migrate/20140505215510_copy_failed_jobs_original_id.rb +2 -3
- data/db/migrate/20150807133223_add_max_concurrent_to_jobs.rb +9 -13
- data/db/migrate/20151210162949_improve_max_concurrent.rb +4 -8
- data/db/migrate/20161206323555_add_back_default_string_limits_jobs.rb +3 -2
- data/db/migrate/20181217155351_speed_up_max_concurrent_triggers.rb +13 -17
- data/db/migrate/20200330230722_add_id_to_get_delayed_jobs_index.rb +8 -8
- data/db/migrate/20200824222232_speed_up_max_concurrent_delete_trigger.rb +72 -77
- data/db/migrate/20200825011002_add_strand_order_override.rb +93 -97
- data/db/migrate/20210809145804_add_n_strand_index.rb +12 -0
- data/db/migrate/20210812210128_add_singleton_column.rb +200 -0
- data/db/migrate/20210917232626_add_delete_conflicting_singletons_before_unlock_trigger.rb +27 -0
- data/db/migrate/20210928174754_fix_singleton_condition_in_before_insert.rb +56 -0
- data/db/migrate/20210929204903_update_conflicting_singleton_function_to_use_index.rb +27 -0
- data/db/migrate/20211101190934_update_after_delete_trigger_for_singleton_index.rb +137 -0
- data/db/migrate/20211207094200_update_after_delete_trigger_for_singleton_transition_cases.rb +171 -0
- data/db/migrate/20211220112800_fix_singleton_race_condition_insert.rb +59 -0
- data/db/migrate/20211220113000_fix_singleton_race_condition_delete.rb +207 -0
- data/db/migrate/20220127091200_fix_singleton_unique_constraint.rb +31 -0
- data/db/migrate/20220128084800_update_insert_trigger_for_singleton_unique_constraint_change.rb +60 -0
- data/db/migrate/20220128084900_update_delete_trigger_for_singleton_unique_constraint_change.rb +209 -0
- data/db/migrate/20220203063200_remove_old_singleton_index.rb +31 -0
- data/db/migrate/20220328152900_add_failed_jobs_indicies.rb +12 -0
- data/exe/inst_jobs +3 -2
- data/lib/delayed/backend/active_record.rb +226 -168
- data/lib/delayed/backend/base.rb +119 -72
- data/lib/delayed/batch.rb +11 -9
- data/lib/delayed/cli.rb +98 -84
- data/lib/delayed/core_ext/kernel.rb +4 -2
- data/lib/delayed/daemon.rb +70 -74
- data/lib/delayed/job_tracking.rb +26 -25
- data/lib/delayed/lifecycle.rb +28 -23
- data/lib/delayed/log_tailer.rb +17 -17
- data/lib/delayed/logging.rb +13 -16
- data/lib/delayed/message_sending.rb +43 -52
- data/lib/delayed/performable_method.rb +6 -8
- data/lib/delayed/periodic.rb +72 -68
- data/lib/delayed/plugin.rb +2 -4
- data/lib/delayed/pool.rb +205 -168
- data/lib/delayed/rails_reloader_plugin.rb +30 -0
- data/lib/delayed/server/helpers.rb +6 -6
- data/lib/delayed/server.rb +51 -54
- data/lib/delayed/settings.rb +96 -81
- data/lib/delayed/testing.rb +21 -22
- data/lib/delayed/version.rb +1 -1
- data/lib/delayed/work_queue/in_process.rb +21 -17
- data/lib/delayed/work_queue/parent_process/client.rb +55 -53
- data/lib/delayed/work_queue/parent_process/server.rb +245 -207
- data/lib/delayed/work_queue/parent_process.rb +52 -53
- data/lib/delayed/worker/consul_health_check.rb +32 -33
- data/lib/delayed/worker/health_check.rb +35 -27
- data/lib/delayed/worker/null_health_check.rb +3 -1
- data/lib/delayed/worker/process_helper.rb +11 -12
- data/lib/delayed/worker.rb +257 -244
- data/lib/delayed/yaml_extensions.rb +12 -10
- data/lib/delayed_job.rb +37 -37
- data/lib/inst-jobs.rb +1 -1
- data/spec/active_record_job_spec.rb +152 -139
- data/spec/delayed/cli_spec.rb +7 -7
- data/spec/delayed/daemon_spec.rb +10 -9
- data/spec/delayed/message_sending_spec.rb +16 -9
- data/spec/delayed/periodic_spec.rb +14 -21
- data/spec/delayed/server_spec.rb +38 -38
- data/spec/delayed/settings_spec.rb +26 -25
- data/spec/delayed/work_queue/in_process_spec.rb +8 -9
- data/spec/delayed/work_queue/parent_process/client_spec.rb +17 -12
- data/spec/delayed/work_queue/parent_process/server_spec.rb +118 -42
- data/spec/delayed/work_queue/parent_process_spec.rb +21 -23
- data/spec/delayed/worker/consul_health_check_spec.rb +37 -50
- data/spec/delayed/worker/health_check_spec.rb +60 -52
- data/spec/delayed/worker_spec.rb +53 -24
- data/spec/sample_jobs.rb +45 -15
- data/spec/shared/delayed_batch.rb +74 -67
- data/spec/shared/delayed_method.rb +143 -102
- data/spec/shared/performable_method.rb +39 -38
- data/spec/shared/shared_backend.rb +801 -440
- data/spec/shared/testing.rb +14 -14
- data/spec/shared/worker.rb +157 -149
- data/spec/shared_jobs_specs.rb +13 -13
- data/spec/spec_helper.rb +57 -56
- metadata +183 -103
- data/lib/delayed/backend/redis/bulk_update.lua +0 -50
- data/lib/delayed/backend/redis/destroy_job.lua +0 -2
- data/lib/delayed/backend/redis/enqueue.lua +0 -29
- data/lib/delayed/backend/redis/fail_job.lua +0 -5
- data/lib/delayed/backend/redis/find_available.lua +0 -3
- data/lib/delayed/backend/redis/functions.rb +0 -59
- data/lib/delayed/backend/redis/get_and_lock_next_available.lua +0 -17
- data/lib/delayed/backend/redis/includes/jobs_common.lua +0 -203
- data/lib/delayed/backend/redis/job.rb +0 -535
- data/lib/delayed/backend/redis/set_running.lua +0 -5
- data/lib/delayed/backend/redis/tickle_strand.lua +0 -2
- data/spec/gemfiles/42.gemfile +0 -7
- data/spec/gemfiles/50.gemfile +0 -7
- data/spec/gemfiles/51.gemfile +0 -7
- data/spec/gemfiles/52.gemfile +0 -7
- data/spec/gemfiles/60.gemfile +0 -7
- data/spec/redis_job_spec.rb +0 -148
    
        data/spec/shared/testing.rb
    CHANGED
    
    | @@ -1,28 +1,28 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
               | 
| 5 | 
            -
                cattr_accessor :runs
         | 
| 3 | 
            +
            class TestingWorker
         | 
| 4 | 
            +
              cattr_accessor :runs
         | 
| 6 5 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
                end
         | 
| 6 | 
            +
              def self.run
         | 
| 7 | 
            +
                self.runs += 1
         | 
| 10 8 | 
             
              end
         | 
| 9 | 
            +
            end
         | 
| 11 10 |  | 
| 11 | 
            +
            shared_examples_for "Delayed::Testing" do
         | 
| 12 12 | 
             
              before do
         | 
| 13 13 | 
             
                TestingWorker.runs = 0
         | 
| 14 14 | 
             
              end
         | 
| 15 15 |  | 
| 16 | 
            -
              describe  | 
| 17 | 
            -
                it  | 
| 16 | 
            +
              describe ".run_job" do
         | 
| 17 | 
            +
                it "runs a single queued job" do
         | 
| 18 18 | 
             
                  job = TestingWorker.delay(ignore_transaction: true).run
         | 
| 19 19 | 
             
                  Delayed::Testing.run_job(job)
         | 
| 20 20 | 
             
                  expect(TestingWorker.runs).to eq 1
         | 
| 21 21 | 
             
                end
         | 
| 22 22 | 
             
              end
         | 
| 23 23 |  | 
| 24 | 
            -
              describe  | 
| 25 | 
            -
                it  | 
| 24 | 
            +
              describe ".drain" do
         | 
| 25 | 
            +
                it "runs all queued jobs" do
         | 
| 26 26 | 
             
                  3.times { TestingWorker.delay.run }
         | 
| 27 27 | 
             
                  YAML.dump(TestingWorker)
         | 
| 28 28 | 
             
                  Delayed::Testing.drain
         | 
| @@ -30,8 +30,8 @@ shared_examples_for 'Delayed::Testing' do | |
| 30 30 | 
             
                end
         | 
| 31 31 | 
             
              end
         | 
| 32 32 |  | 
| 33 | 
            -
              describe  | 
| 34 | 
            -
                it  | 
| 33 | 
            +
              describe "track_created" do
         | 
| 34 | 
            +
                it "returns the list of jobs created in the block" do
         | 
| 35 35 | 
             
                  3.times { TestingWorker.delay.run }
         | 
| 36 36 | 
             
                  jobs = Delayed::Testing.track_created { 2.times { TestingWorker.delay.run } }
         | 
| 37 37 | 
             
                  expect(jobs.size).to eq 2
         | 
| @@ -39,8 +39,8 @@ shared_examples_for 'Delayed::Testing' do | |
| 39 39 | 
             
                end
         | 
| 40 40 | 
             
              end
         | 
| 41 41 |  | 
| 42 | 
            -
              describe  | 
| 43 | 
            -
                it  | 
| 42 | 
            +
              describe "clear_all!" do
         | 
| 43 | 
            +
                it "deletes all queued jobs" do
         | 
| 44 44 | 
             
                  3.times { TestingWorker.delay.run }
         | 
| 45 45 | 
             
                  Delayed::Testing.clear_all!
         | 
| 46 46 | 
             
                  Delayed::Testing.drain
         | 
    
        data/spec/shared/worker.rb
    CHANGED
    
    | @@ -1,18 +1,30 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 3 | 
            +
            class TestPlugin < ::Delayed::Plugin
         | 
| 4 | 
            +
              cattr_accessor :runs
         | 
| 5 | 
            +
              self.runs = 0
         | 
| 6 | 
            +
              callbacks do |lifecycle|
         | 
| 7 | 
            +
                lifecycle.around(:invoke_job) do |job, *args, &block|
         | 
| 8 | 
            +
                  TestPlugin.runs += 1
         | 
| 9 | 
            +
                  block.call(job, *args)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            shared_examples_for "Delayed::Worker" do
         | 
| 4 15 | 
             
              def job_create(opts = {})
         | 
| 5 | 
            -
                Delayed::Job.create({: | 
| 16 | 
            +
                Delayed::Job.create({ payload_object: SimpleJob.new, queue: Delayed::Settings.queue }.merge(opts))
         | 
| 6 17 | 
             
              end
         | 
| 18 | 
            +
             | 
| 7 19 | 
             
              def worker_create(opts = {})
         | 
| 8 | 
            -
                Delayed::Worker.new(opts.merge(: | 
| 20 | 
            +
                Delayed::Worker.new(opts.merge(max_priority: nil, min_priority: nil, quiet: true))
         | 
| 9 21 | 
             
              end
         | 
| 10 22 |  | 
| 11 | 
            -
              before | 
| 23 | 
            +
              before do
         | 
| 12 24 | 
             
                @worker = worker_create
         | 
| 13 25 | 
             
                SimpleJob.runs = 0
         | 
| 14 26 | 
             
                Delayed::Worker.on_max_failures = nil
         | 
| 15 | 
            -
                Delayed::Settings.sleep_delay = ->{ 0.01 }
         | 
| 27 | 
            +
                Delayed::Settings.sleep_delay = -> { 0.01 }
         | 
| 16 28 | 
             
              end
         | 
| 17 29 |  | 
| 18 30 | 
             
              after do
         | 
| @@ -20,8 +32,8 @@ shared_examples_for 'Delayed::Worker' do | |
| 20 32 | 
             
              end
         | 
| 21 33 |  | 
| 22 34 | 
             
              describe "running a job" do
         | 
| 23 | 
            -
                it " | 
| 24 | 
            -
                  @job = "Some % Name here".delay(ignore_transaction: true). | 
| 35 | 
            +
                it "does not fail when running a job with a % in the name" do
         | 
| 36 | 
            +
                  @job = "Some % Name here".delay(ignore_transaction: true).start_with?("Some % Name")
         | 
| 25 37 | 
             
                  @worker.perform(@job)
         | 
| 26 38 | 
             
                end
         | 
| 27 39 | 
             
              end
         | 
| @@ -37,91 +49,99 @@ shared_examples_for 'Delayed::Worker' do | |
| 37 49 | 
             
                    Delayed::Worker.lifecycle.reset!
         | 
| 38 50 | 
             
                  end
         | 
| 39 51 |  | 
| 40 | 
            -
                  it " | 
| 52 | 
            +
                  it "runs each job in order" do
         | 
| 41 53 | 
             
                    bar = +"bar"
         | 
| 42 54 | 
             
                    expect(bar).to receive(:scan).with("b").ordered
         | 
| 43 55 | 
             
                    expect(bar).to receive(:scan).with("a").ordered
         | 
| 44 56 | 
             
                    expect(bar).to receive(:scan).with("r").ordered
         | 
| 45 57 | 
             
                    batch = Delayed::Batch::PerformableBatch.new(:serial, [
         | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 58 | 
            +
                                                                   { payload_object: Delayed::PerformableMethod.new(bar, :scan,
         | 
| 59 | 
            +
                                                                                                                    args: ["b"]) },
         | 
| 60 | 
            +
                                                                   { payload_object: Delayed::PerformableMethod.new(bar, :scan,
         | 
| 61 | 
            +
                                                                                                                    args: ["a"]) },
         | 
| 62 | 
            +
                                                                   { payload_object: Delayed::PerformableMethod.new(bar, :scan,
         | 
| 63 | 
            +
                                                                                                                    args: ["r"]) }
         | 
| 64 | 
            +
                                                                 ])
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                    batch_job = Delayed::Job.create payload_object: batch
         | 
| 67 | 
            +
                    expect(@worker.perform(batch_job)).to eq(3)
         | 
| 68 | 
            +
                    expect(@runs).to be 4 # batch, plus all jobs
         | 
| 54 69 | 
             
                  end
         | 
| 55 70 |  | 
| 56 | 
            -
                  it " | 
| 71 | 
            +
                  it "succeeds regardless of the success/failure of its component jobs" do
         | 
| 57 72 | 
             
                    change_setting(Delayed::Settings, :max_attempts, 2) do
         | 
| 58 73 | 
             
                      batch = Delayed::Batch::PerformableBatch.new(:serial, [
         | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
                       | 
| 74 | 
            +
                                                                     { payload_object: Delayed::PerformableMethod.new("foo",
         | 
| 75 | 
            +
                                                                                                                      :reverse) },
         | 
| 76 | 
            +
                                                                     { payload_object: Delayed::PerformableMethod.new(1, :/,
         | 
| 77 | 
            +
                                                                                                                      args: [0]) },
         | 
| 78 | 
            +
                                                                     { payload_object: Delayed::PerformableMethod.new("bar", :scan,
         | 
| 79 | 
            +
                                                                                                                      args: ["r"]) }
         | 
| 80 | 
            +
                                                                   ])
         | 
| 81 | 
            +
                      batch_job = Delayed::Job.create payload_object: batch
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                      expect(@worker.perform(batch_job)).to eq(3)
         | 
| 84 | 
            +
                      expect(@runs).to be 3 # batch, plus two successful jobs
         | 
| 67 85 |  | 
| 68 86 | 
             
                      to_retry = Delayed::Job.list_jobs(:future, 100)
         | 
| 69 | 
            -
                      to_retry.size. | 
| 70 | 
            -
                      to_retry[0].payload_object.method. | 
| 71 | 
            -
                      to_retry[0].last_error. | 
| 72 | 
            -
                      to_retry[0].attempts. | 
| 87 | 
            +
                      expect(to_retry.size).to be 1
         | 
| 88 | 
            +
                      expect(to_retry[0].payload_object.method).to be :/
         | 
| 89 | 
            +
                      expect(to_retry[0].last_error).to match(/divided by 0/)
         | 
| 90 | 
            +
                      expect(to_retry[0].attempts).to eq(1)
         | 
| 73 91 | 
             
                    end
         | 
| 74 92 | 
             
                  end
         | 
| 75 93 |  | 
| 76 | 
            -
                  it " | 
| 94 | 
            +
                  it "retries a failed individual job" do
         | 
| 77 95 | 
             
                    batch = Delayed::Batch::PerformableBatch.new(:serial, [
         | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 96 | 
            +
                                                                   { payload_object: Delayed::PerformableMethod.new(1,
         | 
| 97 | 
            +
                                                                                                                    :/,
         | 
| 98 | 
            +
                                                                                                                    args: [0]) }
         | 
| 99 | 
            +
                                                                 ])
         | 
| 100 | 
            +
                    batch_job = Delayed::Job.create payload_object: batch
         | 
| 81 101 |  | 
| 82 102 | 
             
                    expect_any_instance_of(Delayed::Job).to receive(:reschedule).once
         | 
| 83 | 
            -
                    @worker.perform(batch_job). | 
| 84 | 
            -
                    expect(@runs).to  | 
| 103 | 
            +
                    expect(@worker.perform(batch_job)).to eq(1)
         | 
| 104 | 
            +
                    expect(@runs).to be 1 # just the batch
         | 
| 85 105 | 
             
                  end
         | 
| 86 106 | 
             
                end
         | 
| 87 107 | 
             
              end
         | 
| 88 108 |  | 
| 89 109 | 
             
              context "worker prioritization" do
         | 
| 90 | 
            -
                before | 
| 91 | 
            -
                  @worker = Delayed::Worker.new(: | 
| 110 | 
            +
                before do
         | 
| 111 | 
            +
                  @worker = Delayed::Worker.new(max_priority: 5, min_priority: 2, quiet: true)
         | 
| 92 112 | 
             
                end
         | 
| 93 113 |  | 
| 94 | 
            -
                it " | 
| 95 | 
            -
                  SimpleJob.runs. | 
| 114 | 
            +
                it "onlies run jobs that are >= min_priority" do
         | 
| 115 | 
            +
                  expect(SimpleJob.runs).to eq(0)
         | 
| 96 116 |  | 
| 97 | 
            -
                  job_create(: | 
| 98 | 
            -
                  job_create(: | 
| 117 | 
            +
                  job_create(priority: 1)
         | 
| 118 | 
            +
                  job_create(priority: 3)
         | 
| 99 119 | 
             
                  @worker.run
         | 
| 100 120 |  | 
| 101 | 
            -
                  SimpleJob.runs. | 
| 121 | 
            +
                  expect(SimpleJob.runs).to eq(1)
         | 
| 102 122 | 
             
                end
         | 
| 103 123 |  | 
| 104 | 
            -
                it " | 
| 105 | 
            -
                  SimpleJob.runs. | 
| 124 | 
            +
                it "onlies run jobs that are <= max_priority" do
         | 
| 125 | 
            +
                  expect(SimpleJob.runs).to eq(0)
         | 
| 106 126 |  | 
| 107 | 
            -
                  job_create(: | 
| 108 | 
            -
                  job_create(: | 
| 127 | 
            +
                  job_create(priority: 10)
         | 
| 128 | 
            +
                  job_create(priority: 4)
         | 
| 109 129 |  | 
| 110 130 | 
             
                  @worker.run
         | 
| 111 131 |  | 
| 112 | 
            -
                  SimpleJob.runs. | 
| 132 | 
            +
                  expect(SimpleJob.runs).to eq(1)
         | 
| 113 133 | 
             
                end
         | 
| 114 134 | 
             
              end
         | 
| 115 135 |  | 
| 116 136 | 
             
              context "while running with locked jobs" do
         | 
| 117 | 
            -
                it " | 
| 118 | 
            -
                  job_create(: | 
| 119 | 
            -
                   | 
| 137 | 
            +
                it "does not run jobs locked by another worker" do
         | 
| 138 | 
            +
                  job_create(locked_by: "other_worker", locked_at: (Delayed::Job.db_time_now - 1.minute))
         | 
| 139 | 
            +
                  expect { @worker.run }.not_to(change(SimpleJob, :runs))
         | 
| 120 140 | 
             
                end
         | 
| 121 141 |  | 
| 122 | 
            -
                it " | 
| 142 | 
            +
                it "runs open jobs" do
         | 
| 123 143 | 
             
                  job_create
         | 
| 124 | 
            -
                   | 
| 144 | 
            +
                  expect { @worker.run }.to change(SimpleJob, :runs).from(0).to(1)
         | 
| 125 145 | 
             
                end
         | 
| 126 146 | 
             
              end
         | 
| 127 147 |  | 
| @@ -132,74 +152,74 @@ shared_examples_for 'Delayed::Worker' do | |
| 132 152 | 
             
                  @job = Delayed::Job.enqueue ErrorJob.new
         | 
| 133 153 | 
             
                end
         | 
| 134 154 |  | 
| 135 | 
            -
                it " | 
| 155 | 
            +
                it "records last_error when destroy_failed_jobs = false, max_attempts = 1" do
         | 
| 136 156 | 
             
                  Delayed::Worker.on_max_failures = proc { false }
         | 
| 137 157 | 
             
                  @job.max_attempts = 1
         | 
| 138 158 | 
             
                  @job.save!
         | 
| 139 | 
            -
                  (job = Delayed::Job.get_and_lock_next_available( | 
| 159 | 
            +
                  expect(job = Delayed::Job.get_and_lock_next_available("w1")).to eq(@job)
         | 
| 140 160 | 
             
                  @worker.perform(job)
         | 
| 141 161 | 
             
                  old_id = @job.id
         | 
| 142 162 | 
             
                  @job = Delayed::Job.list_jobs(:failed, 1).first
         | 
| 143 | 
            -
                  @job.original_job_id. | 
| 144 | 
            -
                  @job.last_error. | 
| 145 | 
            -
                  @job.last_error. | 
| 146 | 
            -
                  @job.attempts. | 
| 147 | 
            -
                  @job.failed_at. | 
| 148 | 
            -
                  @job.run_at. | 
| 149 | 
            -
                  @job.run_at. | 
| 163 | 
            +
                  expect(@job.original_job_id).to eq(old_id)
         | 
| 164 | 
            +
                  expect(@job.last_error).to match(/did not work/)
         | 
| 165 | 
            +
                  expect(@job.last_error).to match(%r{shared/worker.rb})
         | 
| 166 | 
            +
                  expect(@job.attempts).to eq(1)
         | 
| 167 | 
            +
                  expect(@job.failed_at).not_to be_nil
         | 
| 168 | 
            +
                  expect(@job.run_at).to be > Delayed::Job.db_time_now - 10.minutes
         | 
| 169 | 
            +
                  expect(@job.run_at).to be < Delayed::Job.db_time_now + 10.minutes
         | 
| 150 170 | 
             
                  # job stays locked after failing, for record keeping of time/worker
         | 
| 151 | 
            -
                  @job. | 
| 171 | 
            +
                  expect(@job).to be_locked
         | 
| 152 172 |  | 
| 153 | 
            -
                  Delayed::Job.find_available(100, @job.queue). | 
| 173 | 
            +
                  expect(Delayed::Job.find_available(100, @job.queue)).to eq([])
         | 
| 154 174 | 
             
                end
         | 
| 155 175 |  | 
| 156 | 
            -
                it " | 
| 176 | 
            +
                it "re-schedules jobs after failing" do
         | 
| 157 177 | 
             
                  @worker.perform(@job)
         | 
| 158 178 | 
             
                  @job = Delayed::Job.find(@job.id)
         | 
| 159 | 
            -
                  @job.last_error. | 
| 160 | 
            -
                  @job.last_error. | 
| 161 | 
            -
                  @job.attempts. | 
| 162 | 
            -
                  @job.run_at. | 
| 163 | 
            -
                  @job.run_at. | 
| 179 | 
            +
                  expect(@job.last_error).to match(/did not work/)
         | 
| 180 | 
            +
                  expect(@job.last_error).to match(/sample_jobs.rb:22:in `perform'/)
         | 
| 181 | 
            +
                  expect(@job.attempts).to eq(1)
         | 
| 182 | 
            +
                  expect(@job.run_at).to be > Delayed::Job.db_time_now - 10.minutes
         | 
| 183 | 
            +
                  expect(@job.run_at).to be < Delayed::Job.db_time_now + 10.minutes
         | 
| 164 184 | 
             
                end
         | 
| 165 185 |  | 
| 166 | 
            -
                it " | 
| 186 | 
            +
                it "accepts :unlock return value from on_failure during reschedule and unlock the job" do
         | 
| 167 187 | 
             
                  expect_any_instance_of(Delayed::Job).to receive(:unlock).once
         | 
| 168 188 | 
             
                  @job = Delayed::Job.enqueue(UnlockJob.new(1))
         | 
| 169 189 | 
             
                  @worker.perform(@job)
         | 
| 170 190 | 
             
                end
         | 
| 171 191 |  | 
| 172 | 
            -
                it " | 
| 192 | 
            +
                it "notifies jobs on failure" do
         | 
| 173 193 | 
             
                  ErrorJob.failure_runs = 0
         | 
| 174 194 | 
             
                  @worker.perform(@job)
         | 
| 175 | 
            -
                  ErrorJob.failure_runs. | 
| 195 | 
            +
                  expect(ErrorJob.failure_runs).to eq(1)
         | 
| 176 196 | 
             
                end
         | 
| 177 197 |  | 
| 178 | 
            -
                it " | 
| 198 | 
            +
                it "notifies jobs on permanent failure" do
         | 
| 179 199 | 
             
                  (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
         | 
| 180 200 | 
             
                  ErrorJob.permanent_failure_runs = 0
         | 
| 181 201 | 
             
                  @worker.perform(@job)
         | 
| 182 | 
            -
                  ErrorJob.permanent_failure_runs. | 
| 202 | 
            +
                  expect(ErrorJob.permanent_failure_runs).to eq(1)
         | 
| 183 203 | 
             
                end
         | 
| 184 204 | 
             
              end
         | 
| 185 205 |  | 
| 186 206 | 
             
              context "reschedule" do
         | 
| 187 207 | 
             
                before do
         | 
| 188 | 
            -
                  @job = Delayed::Job.create : | 
| 208 | 
            +
                  @job = Delayed::Job.create payload_object: SimpleJob.new
         | 
| 189 209 | 
             
                end
         | 
| 190 210 |  | 
| 191 211 | 
             
                context "and we want to destroy jobs" do
         | 
| 192 | 
            -
                  it " | 
| 212 | 
            +
                  it "is destroyed if it failed more than Settings.max_attempts times" do
         | 
| 193 213 | 
             
                    expect(@job).to receive(:destroy)
         | 
| 194 214 | 
             
                    Delayed::Settings.max_attempts.times { @job.reschedule }
         | 
| 195 215 | 
             
                  end
         | 
| 196 216 |  | 
| 197 | 
            -
                  it " | 
| 198 | 
            -
                    expect(@job). | 
| 217 | 
            +
                  it "is not destroyed if failed fewer than Settings.max_attempts times" do
         | 
| 218 | 
            +
                    expect(@job).not_to receive(:destroy)
         | 
| 199 219 | 
             
                    (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
         | 
| 200 220 | 
             
                  end
         | 
| 201 221 |  | 
| 202 | 
            -
                  it " | 
| 222 | 
            +
                  it "is destroyed if failed more than Job#max_attempts times" do
         | 
| 203 223 | 
             
                    Delayed::Settings.max_attempts = 25
         | 
| 204 224 | 
             
                    expect(@job).to receive(:destroy)
         | 
| 205 225 | 
             
                    @job.max_attempts = 2
         | 
| @@ -207,8 +227,8 @@ shared_examples_for 'Delayed::Worker' do | |
| 207 227 | 
             
                    2.times { @job.reschedule }
         | 
| 208 228 | 
             
                  end
         | 
| 209 229 |  | 
| 210 | 
            -
                  it " | 
| 211 | 
            -
                    job = Delayed::Job.create : | 
| 230 | 
            +
                  it "is destroyed if it has expired" do
         | 
| 231 | 
            +
                    job = Delayed::Job.create payload_object: SimpleJob.new, expires_at: Delayed::Job.db_time_now - 1.day
         | 
| 212 232 | 
             
                    expect(job).to receive(:destroy)
         | 
| 213 233 | 
             
                    job.reschedule
         | 
| 214 234 | 
             
                  end
         | 
| @@ -223,38 +243,38 @@ shared_examples_for 'Delayed::Worker' do | |
| 223 243 | 
             
                    Delayed::Worker.on_max_failures = nil
         | 
| 224 244 | 
             
                  end
         | 
| 225 245 |  | 
| 226 | 
            -
                  it " | 
| 227 | 
            -
                    @job.failed_at. | 
| 246 | 
            +
                  it "is failed if it failed more than Settings.max_attempts times" do
         | 
| 247 | 
            +
                    expect(@job.failed_at).to be_nil
         | 
| 228 248 | 
             
                    Delayed::Settings.max_attempts.times { @job.reschedule }
         | 
| 229 | 
            -
                    Delayed::Job.list_jobs(:failed, 100).size. | 
| 249 | 
            +
                    expect(Delayed::Job.list_jobs(:failed, 100).size).to eq(1)
         | 
| 230 250 | 
             
                  end
         | 
| 231 251 |  | 
| 232 | 
            -
                  it " | 
| 252 | 
            +
                  it "is not failed if it failed fewer than Settings.max_attempts times" do
         | 
| 233 253 | 
             
                    (Delayed::Settings.max_attempts - 1).times { @job.reschedule }
         | 
| 234 254 | 
             
                    @job = Delayed::Job.find(@job.id)
         | 
| 235 | 
            -
                    @job.failed_at. | 
| 255 | 
            +
                    expect(@job.failed_at).to be_nil
         | 
| 236 256 | 
             
                  end
         | 
| 237 257 |  | 
| 238 | 
            -
                  it " | 
| 239 | 
            -
                    job = Delayed::Job.create : | 
| 258 | 
            +
                  it "is failed if it has expired" do
         | 
| 259 | 
            +
                    job = Delayed::Job.create payload_object: SimpleJob.new, expires_at: Delayed::Job.db_time_now - 1.day
         | 
| 240 260 | 
             
                    expect(job).to receive(:fail!)
         | 
| 241 261 | 
             
                    job.reschedule
         | 
| 242 262 | 
             
                  end
         | 
| 243 263 | 
             
                end
         | 
| 244 264 |  | 
| 245 265 | 
             
                context "and we give an on_max_failures callback" do
         | 
| 246 | 
            -
                  it " | 
| 247 | 
            -
                    Delayed::Worker.on_max_failures = proc do |job,  | 
| 248 | 
            -
                      job. | 
| 266 | 
            +
                  it "is failed max_attempts times and cb is false" do
         | 
| 267 | 
            +
                    Delayed::Worker.on_max_failures = proc do |job, _ex|
         | 
| 268 | 
            +
                      expect(job).to eq(@job)
         | 
| 249 269 | 
             
                      false
         | 
| 250 270 | 
             
                    end
         | 
| 251 271 | 
             
                    expect(@job).to receive(:fail!)
         | 
| 252 272 | 
             
                    Delayed::Settings.max_attempts.times { @job.reschedule }
         | 
| 253 273 | 
             
                  end
         | 
| 254 274 |  | 
| 255 | 
            -
                  it " | 
| 256 | 
            -
                    Delayed::Worker.on_max_failures = proc do |job,  | 
| 257 | 
            -
                      job. | 
| 275 | 
            +
                  it "is destroyed if it failed max_attempts times and cb is true" do
         | 
| 276 | 
            +
                    Delayed::Worker.on_max_failures = proc do |job, _ex|
         | 
| 277 | 
            +
                      expect(job).to eq(@job)
         | 
| 258 278 | 
             
                      true
         | 
| 259 279 | 
             
                    end
         | 
| 260 280 | 
             
                    expect(@job).to receive(:destroy)
         | 
| @@ -263,68 +283,56 @@ shared_examples_for 'Delayed::Worker' do | |
| 263 283 | 
             
                end
         | 
| 264 284 | 
             
              end
         | 
| 265 285 |  | 
| 266 | 
            -
             | 
| 267 286 | 
             
              context "Queue workers" do
         | 
| 268 | 
            -
                before  | 
| 287 | 
            +
                before do
         | 
| 269 288 | 
             
                  Delayed::Settings.queue = "Queue workers test"
         | 
| 270 | 
            -
                  job_create(: | 
| 271 | 
            -
                  job_create(: | 
| 289 | 
            +
                  job_create(queue: "queue1")
         | 
| 290 | 
            +
                  job_create(queue: "queue2")
         | 
| 272 291 | 
             
                end
         | 
| 273 292 |  | 
| 274 | 
            -
                it " | 
| 275 | 
            -
                  worker = worker_create(: | 
| 276 | 
            -
                  SimpleJob.runs. | 
| 293 | 
            +
                it "onlies work off jobs assigned to themselves" do
         | 
| 294 | 
            +
                  worker = worker_create(queue: "queue1")
         | 
| 295 | 
            +
                  expect(SimpleJob.runs).to eq(0)
         | 
| 277 296 | 
             
                  worker.run
         | 
| 278 | 
            -
                  SimpleJob.runs. | 
| 297 | 
            +
                  expect(SimpleJob.runs).to eq(1)
         | 
| 279 298 |  | 
| 280 299 | 
             
                  SimpleJob.runs = 0
         | 
| 281 300 |  | 
| 282 | 
            -
                  worker = worker_create(: | 
| 283 | 
            -
                  SimpleJob.runs. | 
| 301 | 
            +
                  worker = worker_create(queue: "queue2")
         | 
| 302 | 
            +
                  expect(SimpleJob.runs).to eq(0)
         | 
| 284 303 | 
             
                  worker.run
         | 
| 285 | 
            -
                  SimpleJob.runs. | 
| 304 | 
            +
                  expect(SimpleJob.runs).to eq(1)
         | 
| 286 305 | 
             
                end
         | 
| 287 306 |  | 
| 288 | 
            -
                it " | 
| 289 | 
            -
                  worker = worker_create(: | 
| 307 | 
            +
                it "does not work off jobs not assigned to themselves" do
         | 
| 308 | 
            +
                  worker = worker_create(queue: "queue3")
         | 
| 290 309 |  | 
| 291 | 
            -
                  SimpleJob.runs. | 
| 310 | 
            +
                  expect(SimpleJob.runs).to eq(0)
         | 
| 292 311 | 
             
                  worker.run
         | 
| 293 | 
            -
                  SimpleJob.runs. | 
| 312 | 
            +
                  expect(SimpleJob.runs).to eq(0)
         | 
| 294 313 | 
             
                end
         | 
| 295 314 |  | 
| 296 | 
            -
                it " | 
| 315 | 
            +
                it "gets the default queue if none is set" do
         | 
| 297 316 | 
             
                  queue_name = "default_queue"
         | 
| 298 317 | 
             
                  Delayed::Settings.queue = queue_name
         | 
| 299 | 
            -
                  worker = worker_create(: | 
| 300 | 
            -
                  worker.queue_name. | 
| 318 | 
            +
                  worker = worker_create(queue: nil)
         | 
| 319 | 
            +
                  expect(worker.queue_name).to eq(queue_name)
         | 
| 301 320 | 
             
                end
         | 
| 302 321 |  | 
| 303 | 
            -
                it " | 
| 322 | 
            +
                it "overrides default queue name if specified in initialize" do
         | 
| 304 323 | 
             
                  queue_name = "my_queue"
         | 
| 305 324 | 
             
                  Delayed::Settings.queue = "default_queue"
         | 
| 306 | 
            -
                  worker = worker_create(: | 
| 307 | 
            -
                  worker.queue_name. | 
| 325 | 
            +
                  worker = worker_create(queue: queue_name)
         | 
| 326 | 
            +
                  expect(worker.queue_name).to eq(queue_name)
         | 
| 308 327 | 
             
                end
         | 
| 309 328 | 
             
              end
         | 
| 310 329 |  | 
| 311 330 | 
             
              context "plugins" do
         | 
| 312 | 
            -
                 | 
| 313 | 
            -
                  cattr_accessor :runs
         | 
| 314 | 
            -
                  self.runs = 0
         | 
| 315 | 
            -
                  callbacks do |lifecycle|
         | 
| 316 | 
            -
                    lifecycle.around(:invoke_job) do |job, *args, &block|
         | 
| 317 | 
            -
                      TestPlugin.runs += 1
         | 
| 318 | 
            -
                      block.call(job, *args)
         | 
| 319 | 
            -
                    end
         | 
| 320 | 
            -
                  end
         | 
| 321 | 
            -
                end
         | 
| 322 | 
            -
             | 
| 323 | 
            -
                it "should create and call the plugin callbacks" do
         | 
| 331 | 
            +
                it "creates and call the plugin callbacks" do
         | 
| 324 332 | 
             
                  TestPlugin.runs = 0
         | 
| 325 333 | 
             
                  Delayed::Worker.plugins << TestPlugin
         | 
| 326 334 | 
             
                  job_create
         | 
| 327 | 
            -
                  @worker = Delayed::Worker.new(: | 
| 335 | 
            +
                  @worker = Delayed::Worker.new(quiet: true)
         | 
| 328 336 | 
             
                  @worker.run
         | 
| 329 337 | 
             
                  expect(TestPlugin.runs).to eq(1)
         | 
| 330 338 | 
             
                  expect(SimpleJob.runs).to eq(1)
         | 
| @@ -332,52 +340,52 @@ shared_examples_for 'Delayed::Worker' do | |
| 332 340 | 
             
              end
         | 
| 333 341 |  | 
| 334 342 | 
             
              describe "expires_at" do
         | 
| 335 | 
            -
                it " | 
| 336 | 
            -
                  Delayed::Job.enqueue SimpleJob.new, : | 
| 337 | 
            -
                  expect { @worker.run }.to change  | 
| 343 | 
            +
                it "runs non-expired jobs" do
         | 
| 344 | 
            +
                  Delayed::Job.enqueue SimpleJob.new, expires_at: Delayed::Job.db_time_now + 1.day
         | 
| 345 | 
            +
                  expect { @worker.run }.to change(SimpleJob, :runs).by(1)
         | 
| 338 346 | 
             
                end
         | 
| 339 347 |  | 
| 340 | 
            -
                it " | 
| 341 | 
            -
                  Delayed::Job.enqueue SimpleJob.new, : | 
| 342 | 
            -
                  expect { @worker.run }.to change  | 
| 348 | 
            +
                it "does not run expired jobs" do
         | 
| 349 | 
            +
                  Delayed::Job.enqueue SimpleJob.new, expires_at: Delayed::Job.db_time_now - 1.day
         | 
| 350 | 
            +
                  expect { @worker.run }.to change(SimpleJob, :runs).by(0)
         | 
| 343 351 | 
             
                end
         | 
| 344 352 |  | 
| 345 | 
            -
                it " | 
| 353 | 
            +
                it "reports a permanent failure when an expired job is dequeued" do
         | 
| 346 354 | 
             
                  ErrorJob.last_error = nil
         | 
| 347 | 
            -
                  Delayed::Job.enqueue ErrorJob.new, : | 
| 348 | 
            -
                  expect { @worker.run }.to change  | 
| 355 | 
            +
                  Delayed::Job.enqueue ErrorJob.new, expires_at: Delayed::Job.db_time_now - 1.day
         | 
| 356 | 
            +
                  expect { @worker.run }.to change(ErrorJob, :permanent_failure_runs).by(1)
         | 
| 349 357 | 
             
                  expect(ErrorJob.last_error).to be_a Delayed::Backend::JobExpired
         | 
| 350 358 | 
             
                end
         | 
| 351 359 | 
             
              end
         | 
| 352 360 |  | 
| 353 361 | 
             
              describe "delay failure callbacks" do
         | 
| 354 | 
            -
                it " | 
| 362 | 
            +
                it "calls the on_failure callback" do
         | 
| 355 363 | 
             
                  ErrorJob.last_error = nil
         | 
| 356 364 | 
             
                  ErrorJob.new.delay(max_attempts: 2, on_failure: :on_failure).perform
         | 
| 357 | 
            -
                  expect { @worker.run }.to change  | 
| 358 | 
            -
                  expect(ErrorJob.last_error.to_s).to eq  | 
| 365 | 
            +
                  expect { @worker.run }.to change(ErrorJob, :failure_runs).by(1)
         | 
| 366 | 
            +
                  expect(ErrorJob.last_error.to_s).to eq "did not work"
         | 
| 359 367 | 
             
                end
         | 
| 360 368 |  | 
| 361 | 
            -
                it " | 
| 369 | 
            +
                it "calls the on_permanent_failure callback" do
         | 
| 362 370 | 
             
                  ErrorJob.last_error = nil
         | 
| 363 371 | 
             
                  ErrorJob.new.delay(max_attempts: 1, on_permanent_failure: :on_failure).perform
         | 
| 364 | 
            -
                  expect { @worker.run }.to change  | 
| 365 | 
            -
                  expect(ErrorJob.last_error.to_s).to eq  | 
| 372 | 
            +
                  expect { @worker.run }.to change(ErrorJob, :failure_runs).by(1)
         | 
| 373 | 
            +
                  expect(ErrorJob.last_error.to_s).to eq "did not work"
         | 
| 366 374 | 
             
                end
         | 
| 367 375 | 
             
              end
         | 
| 368 376 |  | 
| 369 377 | 
             
              describe "custom deserialization errors" do
         | 
| 370 | 
            -
                it " | 
| 371 | 
            -
                  job = Delayed::Job.create({: | 
| 378 | 
            +
                it "reschedules with more attempts left" do
         | 
| 379 | 
            +
                  job = Delayed::Job.create({ payload_object: DeserializeErrorJob.new, max_attempts: 2 })
         | 
| 372 380 | 
             
                  job.instance_variable_set("@payload_object", nil)
         | 
| 373 | 
            -
                  worker = Delayed::Worker.new(: | 
| 381 | 
            +
                  worker = Delayed::Worker.new(max_priority: nil, min_priority: nil, quiet: true)
         | 
| 374 382 | 
             
                  expect { worker.perform(job) }.not_to raise_error
         | 
| 375 383 | 
             
                end
         | 
| 376 384 |  | 
| 377 385 | 
             
                it "run permanent failure code on last attempt" do
         | 
| 378 | 
            -
                  job = Delayed::Job.create({: | 
| 386 | 
            +
                  job = Delayed::Job.create({ payload_object: DeserializeErrorJob.new, max_attempts: 1 })
         | 
| 379 387 | 
             
                  job.instance_variable_set("@payload_object", nil)
         | 
| 380 | 
            -
                  worker = Delayed::Worker.new(: | 
| 388 | 
            +
                  worker = Delayed::Worker.new(max_priority: nil, min_priority: nil, quiet: true)
         | 
| 381 389 | 
             
                  expect { worker.perform(job) }.not_to raise_error
         | 
| 382 390 | 
             
                end
         | 
| 383 391 | 
             
              end
         | 
| @@ -388,7 +396,7 @@ shared_examples_for 'Delayed::Worker' do | |
| 388 396 | 
             
                  expect(@worker).to receive(:exit?).and_return(true)
         | 
| 389 397 | 
             
                  Delayed::Worker.lifecycle.before(:execute) { |w| w == @worker && fired = true }
         | 
| 390 398 | 
             
                  @worker.start
         | 
| 391 | 
            -
                  expect(fired).to  | 
| 399 | 
            +
                  expect(fired).to be(true)
         | 
| 392 400 | 
             
                end
         | 
| 393 401 | 
             
              end
         | 
| 394 402 |  | 
    
        data/spec/shared_jobs_specs.rb
    CHANGED
    
    | @@ -1,17 +1,17 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 3 | 
            +
            require_relative "shared/delayed_batch"
         | 
| 4 | 
            +
            require_relative "shared/delayed_method"
         | 
| 5 | 
            +
            require_relative "shared/performable_method"
         | 
| 6 | 
            +
            require_relative "shared/shared_backend"
         | 
| 7 | 
            +
            require_relative "shared/testing"
         | 
| 8 | 
            +
            require_relative "shared/worker"
         | 
| 9 9 |  | 
| 10 | 
            -
            shared_examples_for  | 
| 11 | 
            -
              include_examples  | 
| 12 | 
            -
              include_examples  | 
| 13 | 
            -
              include_examples  | 
| 14 | 
            -
              include_examples  | 
| 15 | 
            -
              include_examples  | 
| 16 | 
            -
              include_examples  | 
| 10 | 
            +
            shared_examples_for "a delayed_jobs implementation" do
         | 
| 11 | 
            +
              include_examples "a backend"
         | 
| 12 | 
            +
              include_examples "Delayed::Batch"
         | 
| 13 | 
            +
              include_examples "random ruby objects"
         | 
| 14 | 
            +
              include_examples "Delayed::PerformableMethod"
         | 
| 15 | 
            +
              include_examples "Delayed::Worker"
         | 
| 16 | 
            +
              include_examples "Delayed::Testing"
         | 
| 17 17 | 
             
            end
         |