queue_classic_plus 1.0.0.alpha2 → 4.0.0.alpha8
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 +5 -5
- data/.circleci/config.yml +67 -0
- data/.github/dependabot.yml +8 -0
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/README.md +21 -11
- data/lib/queue_classic_plus/base.rb +43 -8
- data/lib/queue_classic_plus/datadog.rb +11 -0
- data/lib/queue_classic_plus/inheritable_attr.rb +3 -1
- data/lib/queue_classic_plus/metrics.rb +1 -1
- data/lib/queue_classic_plus/new_relic.rb +18 -19
- data/lib/queue_classic_plus/queue_classic/queue.rb +46 -3
- data/lib/queue_classic_plus/tasks/work.rake +16 -2
- data/lib/queue_classic_plus/version.rb +1 -1
- data/lib/queue_classic_plus/worker.rb +67 -25
- data/lib/queue_classic_plus.rb +3 -3
- data/queue_classic_plus.gemspec +8 -2
- data/spec/base_spec.rb +59 -17
- data/spec/datadog_spec.rb +18 -0
- data/spec/helpers.rb +1 -1
- data/spec/new_relic_spec.rb +26 -0
- data/spec/queue_classic/queue_spec.rb +43 -0
- data/spec/sample_jobs.rb +31 -4
- data/spec/spec_helper.rb +5 -0
- data/spec/worker_spec.rb +124 -30
- metadata +46 -11
- data/.travis.yml +0 -8
    
        data/spec/base_spec.rb
    CHANGED
    
    | @@ -12,7 +12,19 @@ describe QueueClassicPlus::Base do | |
| 12 12 | 
             
                  it "does not allow multiple enqueues" do
         | 
| 13 13 | 
             
                    subject.do
         | 
| 14 14 | 
             
                    subject.do
         | 
| 15 | 
            -
                    subject. | 
| 15 | 
            +
                    expect(subject).to have_queue_size_of(1)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  it "checks for an existing job using the same serializing as job enqueuing" do
         | 
| 19 | 
            +
                    # simulate a case where obj#to_json and JSON.dump(obj) do not match
         | 
| 20 | 
            +
                    require 'active_support/core_ext/date_time'
         | 
| 21 | 
            +
                    require 'active_support/json'
         | 
| 22 | 
            +
                    ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    date = DateTime.new(2020, 11, 3)
         | 
| 25 | 
            +
                    subject.do(date)
         | 
| 26 | 
            +
                    subject.do(date)
         | 
| 27 | 
            +
                    expect(subject).to have_queue_size_of(1)
         | 
| 16 28 | 
             
                  end
         | 
| 17 29 |  | 
| 18 30 | 
             
                  it "does allow multiple enqueues if something got locked for too long" do
         | 
| @@ -20,7 +32,7 @@ describe QueueClassicPlus::Base do | |
| 20 32 | 
             
                    one_day_ago = Time.now - 60*60*24
         | 
| 21 33 | 
             
                    execute "UPDATE queue_classic_jobs SET locked_at = '#{one_day_ago}' WHERE q_name = 'test'"
         | 
| 22 34 | 
             
                    subject.do
         | 
| 23 | 
            -
                    subject. | 
| 35 | 
            +
                    expect(subject).to have_queue_size_of(2)
         | 
| 24 36 | 
             
                  end
         | 
| 25 37 | 
             
                end
         | 
| 26 38 |  | 
| @@ -39,13 +51,15 @@ describe QueueClassicPlus::Base do | |
| 39 51 | 
             
                  end
         | 
| 40 52 |  | 
| 41 53 | 
             
                  it "calls perform in a transaction" do
         | 
| 42 | 
            -
                    QueueClassicPlus::Base. | 
| 54 | 
            +
                    expect(QueueClassicPlus::Base).to receive(:transaction).and_call_original
         | 
| 55 | 
            +
             | 
| 43 56 | 
             
                    subject._perform
         | 
| 44 57 | 
             
                  end
         | 
| 45 58 |  | 
| 46 59 | 
             
                  it "measures the time" do
         | 
| 47 | 
            -
                    QueueClassicPlus::Metrics. | 
| 48 | 
            -
             | 
| 60 | 
            +
                    expect(QueueClassicPlus::Metrics).to receive(:timing).with("qu_perform_time", {source: "funky.name"}).and_call_original
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    subject._perform
         | 
| 49 63 | 
             
                  end
         | 
| 50 64 | 
             
                end
         | 
| 51 65 |  | 
| @@ -61,7 +75,8 @@ describe QueueClassicPlus::Base do | |
| 61 75 | 
             
                  end
         | 
| 62 76 |  | 
| 63 77 | 
             
                  it "calls perform outside of a transaction" do
         | 
| 64 | 
            -
                    QueueClassicPlus::Base. | 
| 78 | 
            +
                    expect(QueueClassicPlus::Base).to_not receive(:transaction)
         | 
| 79 | 
            +
             | 
| 65 80 | 
             
                    subject._perform
         | 
| 66 81 | 
             
                  end
         | 
| 67 82 | 
             
                end
         | 
| @@ -79,15 +94,15 @@ describe QueueClassicPlus::Base do | |
| 79 94 | 
             
                  end
         | 
| 80 95 |  | 
| 81 96 | 
             
                  it "retries on specified exception" do
         | 
| 82 | 
            -
                    subject.retries_on?(SomeException.new). | 
| 97 | 
            +
                    expect(subject.retries_on?(SomeException.new)).to be(true)
         | 
| 83 98 | 
             
                  end
         | 
| 84 99 |  | 
| 85 100 | 
             
                  it "does not retry on unspecified exceptions" do
         | 
| 86 | 
            -
                    subject.retries_on?(RuntimeError). | 
| 101 | 
            +
                    expect(subject.retries_on?(RuntimeError)).to be(false)
         | 
| 87 102 | 
             
                  end
         | 
| 88 103 |  | 
| 89 104 | 
             
                  it "sets max retries" do
         | 
| 90 | 
            -
                    subject.max_retries. | 
| 105 | 
            +
                    expect(subject.max_retries).to eq(5)
         | 
| 91 106 | 
             
                  end
         | 
| 92 107 | 
             
                end
         | 
| 93 108 |  | 
| @@ -104,16 +119,16 @@ describe QueueClassicPlus::Base do | |
| 104 119 | 
             
                  end
         | 
| 105 120 |  | 
| 106 121 | 
             
                  it "retries on all specified exceptions" do
         | 
| 107 | 
            -
                    subject.retries_on?(SomeException.new). | 
| 108 | 
            -
                    subject.retries_on?(SomeOtherException.new). | 
| 122 | 
            +
                    expect(subject.retries_on?(SomeException.new)).to be(true)
         | 
| 123 | 
            +
                    expect(subject.retries_on?(SomeOtherException.new)).to be(true)
         | 
| 109 124 | 
             
                  end
         | 
| 110 125 |  | 
| 111 126 | 
             
                  it "does not retry on unspecified exceptions" do
         | 
| 112 | 
            -
                    subject.retries_on?(RuntimeError). | 
| 127 | 
            +
                    expect(subject.retries_on?(RuntimeError)).to be(false)
         | 
| 113 128 | 
             
                  end
         | 
| 114 129 |  | 
| 115 130 | 
             
                  it "sets max retries" do
         | 
| 116 | 
            -
                    subject.max_retries. | 
| 131 | 
            +
                    expect(subject.max_retries).to eq(5)
         | 
| 117 132 | 
             
                  end
         | 
| 118 133 | 
             
                end
         | 
| 119 134 |  | 
| @@ -133,22 +148,49 @@ describe QueueClassicPlus::Base do | |
| 133 148 | 
             
                  end
         | 
| 134 149 |  | 
| 135 150 | 
             
                  it "retries on a subclass of a specified exception" do
         | 
| 136 | 
            -
                    subject.retries_on?(ServiceReallyUnavailable.new). | 
| 151 | 
            +
                    expect(subject.retries_on?(ServiceReallyUnavailable.new)).to be(true)
         | 
| 137 152 | 
             
                  end
         | 
| 138 153 |  | 
| 139 154 | 
             
                  it "does not retry on unspecified exceptions" do
         | 
| 140 | 
            -
                    subject.retries_on?(RuntimeError). | 
| 155 | 
            +
                    expect(subject.retries_on?(RuntimeError)).to be(false)
         | 
| 141 156 | 
             
                  end
         | 
| 142 157 |  | 
| 143 158 | 
             
                  it "sets max retries" do
         | 
| 144 | 
            -
                    subject.max_retries. | 
| 159 | 
            +
                    expect(subject.max_retries).to eq(5)
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                context "with Rails defined" do
         | 
| 164 | 
            +
                  require 'active_job/arguments'
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                  before { stub_const('Rails', true) }
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                  subject do
         | 
| 169 | 
            +
                    Class.new(QueueClassicPlus::Base) do
         | 
| 170 | 
            +
                      @queue = :test
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                      def self.perform(foo, bar)
         | 
| 173 | 
            +
                      end
         | 
| 174 | 
            +
                    end
         | 
| 175 | 
            +
                  end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                  it "serializes parameters when enqueuing a job" do
         | 
| 178 | 
            +
                    expect(ActiveJob::Arguments).to receive(:serialize).with([42, true])
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                    subject.do(42, true)
         | 
| 181 | 
            +
                  end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                  it "deserializes parameters when performing an enqueued job" do
         | 
| 184 | 
            +
                    expect(ActiveJob::Arguments).to receive(:deserialize).with([42, true]) { [42, true] }
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    subject._perform(42, true)
         | 
| 145 187 | 
             
                  end
         | 
| 146 188 | 
             
                end
         | 
| 147 189 | 
             
              end
         | 
| 148 190 |  | 
| 149 191 | 
             
              describe ".librato_key" do
         | 
| 150 192 | 
             
                it "removes unsupported caracter from the classname" do
         | 
| 151 | 
            -
                  Jobs::Tests::TestJob.librato_key. | 
| 193 | 
            +
                  expect(Jobs::Tests::TestJob.librato_key).to eq('jobs.tests.test_job')
         | 
| 152 194 | 
             
                end
         | 
| 153 195 | 
             
              end
         | 
| 154 196 | 
             
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            describe 'requiring queue_classic_plus/new_relic' do
         | 
| 2 | 
            +
              class FunkyName < QueueClassicPlus::Base
         | 
| 3 | 
            +
                @queue = :test
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def self.perform
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              subject { FunkyName._perform }
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              it 'adds Datadog profiling support' do
         | 
| 12 | 
            +
                require 'queue_classic_plus/datadog'
         | 
| 13 | 
            +
                expect(Datadog.tracer).to receive(:trace).with(
         | 
| 14 | 
            +
                  'qc.job', service_name: 'qc.job', resource: 'FunkyName#perform'
         | 
| 15 | 
            +
                )
         | 
| 16 | 
            +
                subject
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
    
        data/spec/helpers.rb
    CHANGED
    
    
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            describe 'requiring queue_classic_plus/new_relic' do
         | 
| 2 | 
            +
              subject do
         | 
| 3 | 
            +
                Class.new(QueueClassicPlus::Base) do
         | 
| 4 | 
            +
                  @queue = :test
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def self.perform
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def self.name
         | 
| 10 | 
            +
                    'Funky::Name'
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              it 'adds NewRelic profiling support' do
         | 
| 16 | 
            +
                expect(subject).to receive(:perform_action_with_newrelic_trace).once.with({
         | 
| 17 | 
            +
                  name: 'perform',
         | 
| 18 | 
            +
                  class_name: 'Funky::Name',
         | 
| 19 | 
            +
                  category: 'OtherTransaction/QueueClassicPlus',
         | 
| 20 | 
            +
                })
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                subject._perform
         | 
| 23 | 
            +
                require 'queue_classic_plus/new_relic'
         | 
| 24 | 
            +
                subject._perform
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
            require 'active_record'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe QC do
         | 
| 5 | 
            +
              describe ".lock" do
         | 
| 6 | 
            +
                context "with a connection from ActiveRecord that casts return types" do
         | 
| 7 | 
            +
                  before do
         | 
| 8 | 
            +
                    @old_conn_adapter = QC.default_conn_adapter
         | 
| 9 | 
            +
                    @activerecord_conn = ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])
         | 
| 10 | 
            +
                    QC.default_conn_adapter = QC::ConnAdapter.new(
         | 
| 11 | 
            +
                      connection: ActiveRecord::Base.connection.raw_connection
         | 
| 12 | 
            +
                    )
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  after do
         | 
| 16 | 
            +
                    @activerecord_conn.disconnect!
         | 
| 17 | 
            +
                    QC.default_conn_adapter = @old_conn_adapter
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  it "locks the job with remaining_retries" do
         | 
| 21 | 
            +
                    QC.enqueue_retry_in(1, "puts", 5, 2)
         | 
| 22 | 
            +
                    sleep 1
         | 
| 23 | 
            +
                    job = QC.lock
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                    expect(job[:q_name]).to eq("default")
         | 
| 26 | 
            +
                    expect(job[:method]).to eq("puts")
         | 
| 27 | 
            +
                    expect(job[:args][0]).to be(2)
         | 
| 28 | 
            +
                    expect(job[:remaining_retries]).to eq("5")
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                it "locks the job with remaining_retries" do
         | 
| 33 | 
            +
                  QC.enqueue_retry_in(1, "puts", 5, 2)
         | 
| 34 | 
            +
                  sleep 1
         | 
| 35 | 
            +
                  job = QC.lock
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  expect(job[:q_name]).to eq("default")
         | 
| 38 | 
            +
                  expect(job[:method]).to eq("puts")
         | 
| 39 | 
            +
                  expect(job[:args][0]).to be(2)
         | 
| 40 | 
            +
                  expect(job[:remaining_retries]).to eq("5")
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
    
        data/spec/sample_jobs.rb
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            require 'pg'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            class SomeException < RuntimeError
         | 
| 2 4 | 
             
            end
         | 
| 3 5 |  | 
| @@ -12,7 +14,7 @@ module Jobs | |
| 12 14 | 
             
                  @queue = :low
         | 
| 13 15 | 
             
                  retry! on: SomeException, max: 5
         | 
| 14 16 |  | 
| 15 | 
            -
                  def self.perform | 
| 17 | 
            +
                  def self.perform(should_raise)
         | 
| 16 18 | 
             
                    raise SomeException if should_raise
         | 
| 17 19 | 
             
                  end
         | 
| 18 20 | 
             
                end
         | 
| @@ -21,10 +23,11 @@ module Jobs | |
| 21 23 | 
             
                class TestJobNoRetry < QueueClassicPlus::Base
         | 
| 22 24 | 
             
                  class Custom < RuntimeError
         | 
| 23 25 | 
             
                  end
         | 
| 26 | 
            +
                  disable_retries!
         | 
| 24 27 |  | 
| 25 28 | 
             
                  @queue = :low
         | 
| 26 29 |  | 
| 27 | 
            -
                  def self.perform | 
| 30 | 
            +
                  def self.perform(should_raise)
         | 
| 28 31 | 
             
                    raise Custom if should_raise
         | 
| 29 32 | 
             
                  end
         | 
| 30 33 | 
             
                end
         | 
| @@ -32,12 +35,36 @@ module Jobs | |
| 32 35 |  | 
| 33 36 | 
             
                class TestJob < QueueClassicPlus::Base
         | 
| 34 37 | 
             
                  @queue = :low
         | 
| 35 | 
            -
                  retry! on: SomeException, max:  | 
| 38 | 
            +
                  retry! on: SomeException, max: 1
         | 
| 36 39 |  | 
| 37 | 
            -
                  def self.perform | 
| 40 | 
            +
                  def self.perform(should_raise)
         | 
| 38 41 | 
             
                    raise SomeException if should_raise
         | 
| 39 42 | 
             
                  end
         | 
| 40 43 | 
             
                end
         | 
| 41 44 |  | 
| 45 | 
            +
                class Exception < RuntimeError
         | 
| 46 | 
            +
                  attr_reader :original_exception
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def initialize(e)
         | 
| 49 | 
            +
                    @original_exception = e
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                class ConnectionReapedTestJob < QueueClassicPlus::Base
         | 
| 54 | 
            +
                  @queue = :low
         | 
| 55 | 
            +
                  retry! on: Exception, max: 5
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def self.perform
         | 
| 58 | 
            +
                    raise Exception.new(PG::UnableToSend.new)
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                class UniqueViolationTestJob < QueueClassicPlus::Base
         | 
| 63 | 
            +
                  @queue = :low
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  def self.perform
         | 
| 66 | 
            +
                    raise Exception.new(PG::UniqueViolation.new)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                end
         | 
| 42 69 | 
             
              end
         | 
| 43 70 | 
             
            end
         | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -4,8 +4,11 @@ require 'timecop' | |
| 4 4 | 
             
            require 'queue_classic_matchers'
         | 
| 5 5 | 
             
            require_relative './sample_jobs'
         | 
| 6 6 | 
             
            require_relative './helpers'
         | 
| 7 | 
            +
            require 'byebug'
         | 
| 7 8 | 
             
            require 'pry'
         | 
| 9 | 
            +
            require 'ddtrace'
         | 
| 8 10 |  | 
| 11 | 
            +
            ENV["QC_RAILS_DATABASE"] ||= "false" # test on QC::ConnAdapter by default
         | 
| 9 12 | 
             
            ENV["DATABASE_URL"] ||= "postgres:///queue_classic_plus_test"
         | 
| 10 13 |  | 
| 11 14 | 
             
            RSpec.configure do |config|
         | 
| @@ -20,5 +23,7 @@ RSpec.configure do |config| | |
| 20 23 |  | 
| 21 24 | 
             
              config.before(:each) do
         | 
| 22 25 | 
             
                QC.default_conn_adapter.execute "TRUNCATE queue_classic_jobs;"
         | 
| 26 | 
            +
                # Reset the default (memoized) queue instance between specs
         | 
| 27 | 
            +
                QC.default_queue = nil
         | 
| 23 28 | 
             
              end
         | 
| 24 29 | 
             
            end
         | 
    
        data/spec/worker_spec.rb
    CHANGED
    
    | @@ -9,22 +9,22 @@ describe QueueClassicPlus::CustomWorker do | |
| 9 9 |  | 
| 10 10 | 
             
                it "record failures in the failed queue" do
         | 
| 11 11 | 
             
                  queue.enqueue("Kerklfadsjflaksj", 1, 2, 3)
         | 
| 12 | 
            -
                  failed_queue.count. | 
| 12 | 
            +
                  expect(failed_queue.count).to eq(0)
         | 
| 13 13 | 
             
                  worker.work
         | 
| 14 | 
            -
                  failed_queue.count. | 
| 14 | 
            +
                  expect(failed_queue.count).to eq(1)
         | 
| 15 15 | 
             
                  job = failed_queue.lock
         | 
| 16 | 
            -
                  job[:method]. | 
| 17 | 
            -
                  job[:args]. | 
| 16 | 
            +
                  expect(job[:method]).to eq("Kerklfadsjflaksj")
         | 
| 17 | 
            +
                  expect(job[:args]).to eq([1, 2, 3])
         | 
| 18 18 | 
             
                  full_job = find_job(job[:id])
         | 
| 19 19 |  | 
| 20 | 
            -
                  full_job['last_error']. | 
| 20 | 
            +
                  expect(full_job['last_error']).to_not be_nil
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 23 | 
             
                it "records normal errors" do
         | 
| 24 24 | 
             
                  queue.enqueue("Jobs::Tests::TestJobNoRetry.perform", true)
         | 
| 25 | 
            -
                  failed_queue.count. | 
| 25 | 
            +
                  expect(failed_queue.count).to eq(0)
         | 
| 26 26 | 
             
                  worker.work
         | 
| 27 | 
            -
                  failed_queue.count. | 
| 27 | 
            +
                  expect(failed_queue.count).to eq(1)
         | 
| 28 28 | 
             
                end
         | 
| 29 29 | 
             
              end
         | 
| 30 30 |  | 
| @@ -42,47 +42,141 @@ describe QueueClassicPlus::CustomWorker do | |
| 42 42 | 
             
                    job_type.enqueue_perform(true)
         | 
| 43 43 | 
             
                  end.to change_queue_size_of(job_type).by(1)
         | 
| 44 44 |  | 
| 45 | 
            -
                  Jobs::Tests::LockedTestJob. | 
| 46 | 
            -
                  failed_queue.count. | 
| 47 | 
            -
                  QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']. | 
| 45 | 
            +
                  expect(Jobs::Tests::LockedTestJob).to have_queue_size_of(1)
         | 
| 46 | 
            +
                  expect(failed_queue.count).to eq(0)
         | 
| 47 | 
            +
                  expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to be_nil
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                  expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil )
         | 
| 48 50 |  | 
| 49 51 | 
             
                  Timecop.freeze do
         | 
| 50 52 | 
             
                    worker.work
         | 
| 51 53 |  | 
| 52 | 
            -
                    failed_queue.count. | 
| 53 | 
            -
                    QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']. | 
| 54 | 
            -
                    Jobs::Tests::LockedTestJob. | 
| 54 | 
            +
                    expect(failed_queue.count).to eq(0) # not enqueued on Failed
         | 
| 55 | 
            +
                    expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to eq "4"
         | 
| 56 | 
            +
                    expect(Jobs::Tests::LockedTestJob).to have_scheduled(true).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
         | 
| 55 57 | 
             
                  end
         | 
| 56 58 |  | 
| 57 59 | 
             
                  Timecop.freeze(Time.now + (described_class::BACKOFF_WIDTH * 2)) do
         | 
| 58 60 | 
             
                    # the job should be re-enqueued with a decremented retry count
         | 
| 59 61 | 
             
                    jobs = QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true])
         | 
| 60 | 
            -
                    jobs.size. | 
| 62 | 
            +
                    expect(jobs.size).to eq(1)
         | 
| 61 63 | 
             
                    job = jobs.first
         | 
| 62 | 
            -
                    job['remaining_retries'].to_i. | 
| 63 | 
            -
                    job['locked_by']. | 
| 64 | 
            -
                    job['locked_at']. | 
| 64 | 
            +
                    expect(job['remaining_retries'].to_i).to eq(job_type.max_retries - 1)
         | 
| 65 | 
            +
                    expect(job['locked_by']).to be_nil
         | 
| 66 | 
            +
                    expect(job['locked_at']).to be_nil
         | 
| 65 67 | 
             
                  end
         | 
| 66 68 | 
             
                end
         | 
| 67 69 |  | 
| 68 | 
            -
                 | 
| 69 | 
            -
                   | 
| 70 | 
            -
                   | 
| 71 | 
            -
                    job_type.enqueue_perform(true)
         | 
| 72 | 
            -
                  end.to change_queue_size_of(job_type).by(1)
         | 
| 70 | 
            +
                context 'when Rails is defined' do
         | 
| 71 | 
            +
                  require 'active_job'
         | 
| 72 | 
            +
                  require 'active_job/arguments'
         | 
| 73 73 |  | 
| 74 | 
            -
                   | 
| 75 | 
            -
             | 
| 76 | 
            -
                   | 
| 74 | 
            +
                  before { stub_const('Rails', Struct.new(:logger).new(Logger.new(STDOUT))) }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  it 'retries' do
         | 
| 77 | 
            +
                    expect do
         | 
| 78 | 
            +
                      job_type.enqueue_perform(:foo)
         | 
| 79 | 
            +
                    end.to change_queue_size_of(job_type).by(1)
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                    expect(Jobs::Tests::LockedTestJob).to have_queue_size_of(1)
         | 
| 82 | 
            +
                    expect(failed_queue.count).to eq(0)
         | 
| 83 | 
            +
                    expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [:foo]).first['remaining_retries']).to be_nil
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil).twice
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    Timecop.freeze do
         | 
| 88 | 
            +
                      worker.work
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                      expect(failed_queue.count).to eq(0) # not enqueued on Failed
         | 
| 91 | 
            +
                      expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [:foo]).first['remaining_retries']).to eq "4"
         | 
| 92 | 
            +
                      expect(Jobs::Tests::LockedTestJob).to have_scheduled(:foo).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
         | 
| 93 | 
            +
                    end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                    Timecop.freeze(Time.now + (described_class::BACKOFF_WIDTH * 2)) do
         | 
| 96 | 
            +
                      # the job should be re-enqueued with a decremented retry count
         | 
| 97 | 
            +
                      jobs = QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [:foo])
         | 
| 98 | 
            +
                      expect(jobs.size).to eq(1)
         | 
| 99 | 
            +
                      job = jobs.first
         | 
| 100 | 
            +
                      expect(job['remaining_retries'].to_i).to eq(job_type.max_retries - 1)
         | 
| 101 | 
            +
                      expect(job['locked_by']).to be_nil
         | 
| 102 | 
            +
                      expect(job['locked_at']).to be_nil
         | 
| 103 | 
            +
                    end
         | 
| 77 104 |  | 
| 78 | 
            -
                  Timecop.freeze do
         | 
| 79 105 | 
             
                    worker.work
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                context 'when PG connection reaped during a job' do
         | 
| 110 | 
            +
                  before { Jobs::Tests::ConnectionReapedTestJob.enqueue_perform }
         | 
| 80 111 |  | 
| 81 | 
            -
             | 
| 82 | 
            -
                     | 
| 83 | 
            -
                     | 
| 112 | 
            +
                  it 'retries' do
         | 
| 113 | 
            +
                    expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.force_retry', source: nil )
         | 
| 114 | 
            +
                    Timecop.freeze do
         | 
| 115 | 
            +
                      worker.work
         | 
| 116 | 
            +
                      expect(failed_queue.count).to eq 0
         | 
| 117 | 
            +
                      expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::ConnectionReapedTestJob._perform', []).first['remaining_retries']).to eq "4"
         | 
| 118 | 
            +
                    end
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  it 'ensures to rollback' do
         | 
| 122 | 
            +
                    allow(QC.default_conn_adapter).to receive(:execute).and_call_original
         | 
| 123 | 
            +
                    expect(QC.default_conn_adapter).to receive(:execute).with('ROLLBACK')
         | 
| 124 | 
            +
                    Timecop.freeze do
         | 
| 125 | 
            +
                      worker.work
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                context 'with a custom exception having max: 1 retry' do
         | 
| 131 | 
            +
                  before { Jobs::Tests::TestJob.enqueue_perform(true) }
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  it 'retries' do
         | 
| 134 | 
            +
                    expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil )
         | 
| 135 | 
            +
                    Timecop.freeze do
         | 
| 136 | 
            +
                      worker.work
         | 
| 137 | 
            +
                      expect(failed_queue.count).to eq 0
         | 
| 138 | 
            +
                      expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::TestJob._perform', [true]).first['remaining_retries']).to eq "0"
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                context 'with non-connection based PG jobs' do
         | 
| 144 | 
            +
                  before { Jobs::Tests::UniqueViolationTestJob.enqueue_perform }
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                  it 'sends the job to the failed jobs queue' do
         | 
| 147 | 
            +
                    Timecop.freeze do
         | 
| 148 | 
            +
                      worker.work
         | 
| 149 | 
            +
                    end
         | 
| 150 | 
            +
                    expect(failed_queue.count).to eq 1
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
                end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                context 'when retries have been exhausted' do
         | 
| 155 | 
            +
                  before do
         | 
| 156 | 
            +
                    job_type.max_retries = 0
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                  after do
         | 
| 160 | 
            +
                    job_type.max_retries = 5
         | 
| 161 | 
            +
                  end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                  it 'enqueues in the failed queue' do
         | 
| 164 | 
            +
                    expect do
         | 
| 165 | 
            +
                      job_type.enqueue_perform(true)
         | 
| 166 | 
            +
                    end.to change_queue_size_of(job_type).by(1)
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                    expect(Jobs::Tests::LockedTestJob).to have_queue_size_of(1)
         | 
| 169 | 
            +
                    expect(failed_queue.count).to eq(0)
         | 
| 170 | 
            +
                    expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to be_nil
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                    Timecop.freeze do
         | 
| 173 | 
            +
                      worker.work
         | 
| 174 | 
            +
             | 
| 175 | 
            +
                      expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('failed_jobs', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to be_nil
         | 
| 176 | 
            +
                      expect(failed_queue.count).to eq(1) # not enqueued on Failed
         | 
| 177 | 
            +
                      expect(Jobs::Tests::LockedTestJob).to_not have_scheduled(true).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
         | 
| 178 | 
            +
                    end
         | 
| 84 179 | 
             
                  end
         | 
| 85 180 | 
             
                end
         | 
| 86 181 | 
             
              end
         | 
| 87 182 | 
             
            end
         | 
| 88 | 
            -
             | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: queue_classic_plus
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version:  | 
| 4 | 
            +
              version: 4.0.0.alpha8
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Simon Mathieu
         | 
| @@ -10,36 +10,36 @@ authors: | |
| 10 10 | 
             
            autorequire: 
         | 
| 11 11 | 
             
            bindir: bin
         | 
| 12 12 | 
             
            cert_chain: []
         | 
| 13 | 
            -
            date:  | 
| 13 | 
            +
            date: 2021-10-12 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies:
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 16 16 | 
             
              name: queue_classic
         | 
| 17 17 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 18 18 | 
             
                requirements:
         | 
| 19 | 
            -
                - -  | 
| 19 | 
            +
                - - '='
         | 
| 20 20 | 
             
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            -
                    version:  | 
| 21 | 
            +
                    version: 4.0.0.pre.alpha1
         | 
| 22 22 | 
             
              type: :runtime
         | 
| 23 23 | 
             
              prerelease: false
         | 
| 24 24 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 25 | 
             
                requirements:
         | 
| 26 | 
            -
                - -  | 
| 26 | 
            +
                - - '='
         | 
| 27 27 | 
             
                  - !ruby/object:Gem::Version
         | 
| 28 | 
            -
                    version:  | 
| 28 | 
            +
                    version: 4.0.0.pre.alpha1
         | 
| 29 29 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 30 30 | 
             
              name: bundler
         | 
| 31 31 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 32 32 | 
             
                requirements:
         | 
| 33 33 | 
             
                - - "~>"
         | 
| 34 34 | 
             
                  - !ruby/object:Gem::Version
         | 
| 35 | 
            -
                    version: ' | 
| 35 | 
            +
                    version: '2.0'
         | 
| 36 36 | 
             
              type: :development
         | 
| 37 37 | 
             
              prerelease: false
         | 
| 38 38 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 39 39 | 
             
                requirements:
         | 
| 40 40 | 
             
                - - "~>"
         | 
| 41 41 | 
             
                  - !ruby/object:Gem::Version
         | 
| 42 | 
            -
                    version: ' | 
| 42 | 
            +
                    version: '2.0'
         | 
| 43 43 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 44 44 | 
             
              name: rake
         | 
| 45 45 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -54,6 +54,34 @@ dependencies: | |
| 54 54 | 
             
                - - ">="
         | 
| 55 55 | 
             
                  - !ruby/object:Gem::Version
         | 
| 56 56 | 
             
                    version: '0'
         | 
| 57 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 58 | 
            +
              name: activerecord
         | 
| 59 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 60 | 
            +
                requirements:
         | 
| 61 | 
            +
                - - "~>"
         | 
| 62 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 63 | 
            +
                    version: '6.0'
         | 
| 64 | 
            +
              type: :development
         | 
| 65 | 
            +
              prerelease: false
         | 
| 66 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 67 | 
            +
                requirements:
         | 
| 68 | 
            +
                - - "~>"
         | 
| 69 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 70 | 
            +
                    version: '6.0'
         | 
| 71 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 72 | 
            +
              name: activejob
         | 
| 73 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 74 | 
            +
                requirements:
         | 
| 75 | 
            +
                - - ">="
         | 
| 76 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 77 | 
            +
                    version: '0'
         | 
| 78 | 
            +
              type: :development
         | 
| 79 | 
            +
              prerelease: false
         | 
| 80 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 81 | 
            +
                requirements:
         | 
| 82 | 
            +
                - - ">="
         | 
| 83 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 84 | 
            +
                    version: '0'
         | 
| 57 85 | 
             
            description: ''
         | 
| 58 86 | 
             
            email:
         | 
| 59 87 | 
             
            - simon.math@gmail.com
         | 
| @@ -63,10 +91,11 @@ executables: [] | |
| 63 91 | 
             
            extensions: []
         | 
| 64 92 | 
             
            extra_rdoc_files: []
         | 
| 65 93 | 
             
            files:
         | 
| 94 | 
            +
            - ".circleci/config.yml"
         | 
| 95 | 
            +
            - ".github/dependabot.yml"
         | 
| 66 96 | 
             
            - ".gitignore"
         | 
| 67 97 | 
             
            - ".rspec"
         | 
| 68 98 | 
             
            - ".rvmrc"
         | 
| 69 | 
            -
            - ".travis.yml"
         | 
| 70 99 | 
             
            - Gemfile
         | 
| 71 100 | 
             
            - Guardfile
         | 
| 72 101 | 
             
            - LICENSE.txt
         | 
| @@ -74,6 +103,7 @@ files: | |
| 74 103 | 
             
            - Rakefile
         | 
| 75 104 | 
             
            - lib/queue_classic_plus.rb
         | 
| 76 105 | 
             
            - lib/queue_classic_plus/base.rb
         | 
| 106 | 
            +
            - lib/queue_classic_plus/datadog.rb
         | 
| 77 107 | 
             
            - lib/queue_classic_plus/inflector.rb
         | 
| 78 108 | 
             
            - lib/queue_classic_plus/inheritable_attr.rb
         | 
| 79 109 | 
             
            - lib/queue_classic_plus/metrics.rb
         | 
| @@ -89,8 +119,11 @@ files: | |
| 89 119 | 
             
            - lib/rails/generators/qc_plus_job/templates/job_spec.rb.erb
         | 
| 90 120 | 
             
            - queue_classic_plus.gemspec
         | 
| 91 121 | 
             
            - spec/base_spec.rb
         | 
| 122 | 
            +
            - spec/datadog_spec.rb
         | 
| 92 123 | 
             
            - spec/helpers.rb
         | 
| 93 124 | 
             
            - spec/inflector_spec.rb
         | 
| 125 | 
            +
            - spec/new_relic_spec.rb
         | 
| 126 | 
            +
            - spec/queue_classic/queue_spec.rb
         | 
| 94 127 | 
             
            - spec/sample_jobs.rb
         | 
| 95 128 | 
             
            - spec/spec_helper.rb
         | 
| 96 129 | 
             
            - spec/update_metrics_spec.rb
         | 
| @@ -114,15 +147,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 114 147 | 
             
                - !ruby/object:Gem::Version
         | 
| 115 148 | 
             
                  version: 1.3.1
         | 
| 116 149 | 
             
            requirements: []
         | 
| 117 | 
            -
             | 
| 118 | 
            -
            rubygems_version: 2.2.2
         | 
| 150 | 
            +
            rubygems_version: 3.1.6
         | 
| 119 151 | 
             
            signing_key: 
         | 
| 120 152 | 
             
            specification_version: 4
         | 
| 121 153 | 
             
            summary: Useful extras for Queue Classic
         | 
| 122 154 | 
             
            test_files:
         | 
| 123 155 | 
             
            - spec/base_spec.rb
         | 
| 156 | 
            +
            - spec/datadog_spec.rb
         | 
| 124 157 | 
             
            - spec/helpers.rb
         | 
| 125 158 | 
             
            - spec/inflector_spec.rb
         | 
| 159 | 
            +
            - spec/new_relic_spec.rb
         | 
| 160 | 
            +
            - spec/queue_classic/queue_spec.rb
         | 
| 126 161 | 
             
            - spec/sample_jobs.rb
         | 
| 127 162 | 
             
            - spec/spec_helper.rb
         | 
| 128 163 | 
             
            - spec/update_metrics_spec.rb
         |