queue_classic_plus 1.0.1 → 4.0.0.alpha10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2401a88a47f9dcc2752db9ed026982cb6724851b
4
- data.tar.gz: cecd7627f4a663a4b89a7bf6bfeed08f240cea62
2
+ SHA256:
3
+ metadata.gz: 14e8dfec194b5946e629568f8fc73041f0a9f546b737ab2926446cfa0bffe854
4
+ data.tar.gz: e45cbfdd17b764c9569f554ac989e3ab03948a237265f53605aba8032be28bd1
5
5
  SHA512:
6
- metadata.gz: 4da76e72bfed26e9898a1094cc6cc719caaafcb0efb4cfd59d86f4aa02e716b2ecee592f9a384149e557ca4f67ce9583b22dc4555e09befcbd2bea5586ac40ed
7
- data.tar.gz: 4c6e779b8546ca3c91e925aa0236623516ea009532a14a9e53bf7f0b895a47a6168ddc243fdf17b5cedb8a1dd2f36f97cccd60629b808ea3c1ad81725df01a58
6
+ metadata.gz: 6380f8e7aaacae04565c0d1ed2a6b0bb5a9257709f803efd015914a032d1aa35cf4757c4dee8c7639bf9ec03e92df8352a08dddd0ab1f53ccf85d18c7fa77685
7
+ data.tar.gz: eefd27dce5e3f9e6a5a1c33a5b6572890a29142b2acf9b65dc2802a125b6fa173dedd48e0f216f61f9384bfa10cf13651d6173b8ca1a0d07e4ad66f4201a3ea1
@@ -0,0 +1,67 @@
1
+ version: 2.1
2
+
3
+ jobs:
4
+ test:
5
+ docker:
6
+ - image: cimg/ruby:3.0.3
7
+ auth:
8
+ username: $DOCKERHUB_USERNAME
9
+ password: $DOCKERHUB_TOKEN
10
+ environment:
11
+ DATABASE_URL: postgres://circleci:circleci@127.0.0.1:5432/queue_classic_plus_test
12
+ - image: circleci/postgres:9.6.6-alpine
13
+ auth:
14
+ username: $DOCKERHUB_USERNAME
15
+ password: $DOCKERHUB_TOKEN
16
+ environment:
17
+ POSTGRES_USER: circleci
18
+ POSTGRES_PASSWORD: circleci
19
+ POSTGRES_DB: queue_classic_plus_test
20
+ steps:
21
+ - checkout
22
+ - run:
23
+ name: run tests
24
+ command: |
25
+ bundle check --path=vendor/bundle || bundle install --path=vendor/bundle --jobs=4 --retry=3
26
+ bundle exec rspec
27
+
28
+ push_to_rubygems:
29
+ docker:
30
+ - image: cimg/ruby:3.0.3
31
+ auth:
32
+ username: $DOCKERHUB_USERNAME
33
+ password: $DOCKERHUB_TOKEN
34
+ steps:
35
+ - checkout
36
+ - run:
37
+ name: Create .gem/credentials file
38
+ command: |
39
+ mkdir ~/.gem
40
+ echo "---
41
+ :rubygems_api_key: $RUBYGEMS_API_KEY
42
+ " > ~/.gem/credentials
43
+ chmod 600 ~/.gem/credentials
44
+ - run:
45
+ name: Release to rubygems
46
+ command: |
47
+ gem build queue_classic_plus
48
+ gem push queue_classic_plus-*.gem
49
+
50
+ workflows:
51
+ version: 2
52
+ gem_release:
53
+ jobs:
54
+ - test:
55
+ context:
56
+ - DockerHub
57
+
58
+ - push_to_rubygems:
59
+ filters:
60
+ branches:
61
+ ignore:
62
+ - /.*/
63
+ tags:
64
+ only:
65
+ - /^v.*/
66
+ context:
67
+ - DockerHub
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "13:00"
8
+ open-pull-requests-limit: 10
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *.gem
2
2
  *.rbc
3
3
  .bundle
4
+ .byebug_history
4
5
  .config
5
6
  .yardoc
6
7
  Gemfile.lock
@@ -9,6 +10,7 @@ _yardoc
9
10
  coverage
10
11
  doc/
11
12
  lib/bundler/man
13
+ log/
12
14
  pkg
13
15
  rdoc
14
16
  spec/reports
data/Gemfile CHANGED
@@ -12,7 +12,10 @@ group :development do
12
12
  end
13
13
 
14
14
  group :test do
15
- gem 'rake'
15
+ gem 'byebug'
16
16
  gem 'rspec'
17
17
  gem 'timecop'
18
+ gem 'newrelic_rpm'
19
+ gem 'ddtrace'
20
+ gem 'simplecov', require: false
18
21
  end
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # QueueClassicPlus
2
2
 
3
- [![Build Status](https://travis-ci.org/rainforestapp/queue_classic_plus.svg?branch=master)](https://travis-ci.org/rainforestapp/queue_classic_plus)
3
+ [![rainforestapp](https://circleci.com/gh/rainforestapp/queue_classic_plus.svg?branch=master)](https://app.circleci.com/pipelines/github/rainforestapp/queue_classic_plus?branch=master)
4
4
 
5
5
  [queue_classic](https://github.com/QueueClassic/queue_classic) is a simple Postgresql backed DB queue. However, it's a little too simple to use it as the main queueing system of a medium to large app. This was developed at [Rainforest QA](https://www.rainforestqa.com/).
6
6
 
@@ -130,7 +130,7 @@ If you want to log exceptions in your favorite exception tracker. You can config
130
130
 
131
131
  ```ruby
132
132
  QueueClassicPlus.exception_handler = -> (exception, job) do
133
- Raven.capture_exception(exception, extra: {job: job, env: ENV})
133
+ Sentry.capture_exception(exception, extra: { job: job, env: ENV })
134
134
  end
135
135
  ```
136
136
 
@@ -150,6 +150,12 @@ If you are using NewRelic and want to push performance data to it, you can add t
150
150
  require "queue_classic_plus/new_relic"
151
151
  ```
152
152
 
153
+ To instrument DataDog monitoring add this to your QC initializer:
154
+
155
+ ```ruby
156
+ require "queue_classic_plus/datadog"
157
+ ```
158
+
153
159
  ## Contributing
154
160
 
155
161
  1. Fork it ( https://github.com/[my-github-username]/queue_classic_plus/fork )
@@ -163,3 +169,7 @@ require "queue_classic_plus/new_relic"
163
169
  ```
164
170
  createdb queue_classic_plus_test
165
171
  ```
172
+
173
+ ## Releasing
174
+
175
+ Releasing is done in CircleCI via the `push_to_rubygems`, triggered by pushing a tagged commit. To do so, simply [create a new GitHub release](https://github.com/rainforestapp/queue_classic_plus/releases/new).
@@ -67,7 +67,7 @@ module QueueClassicPlus
67
67
  )
68
68
  AS x"
69
69
 
70
- result = QC.default_conn_adapter.execute(q, @queue, method, args.to_json)
70
+ result = QC.default_conn_adapter.execute(q, @queue, method, JSON.dump(serialized(args)))
71
71
  result['count'].to_i == 0
72
72
  else
73
73
  true
@@ -76,7 +76,7 @@ module QueueClassicPlus
76
76
 
77
77
  def self.enqueue(method, *args)
78
78
  if can_enqueue?(method, *args)
79
- queue.enqueue(method, *args)
79
+ queue.enqueue(method, *serialized(args))
80
80
  end
81
81
  end
82
82
 
@@ -86,11 +86,11 @@ module QueueClassicPlus
86
86
 
87
87
  def self.enqueue_perform_in(time, *args)
88
88
  raise "Can't enqueue in the future for locked jobs" if locked?
89
- queue.enqueue_in(time, "#{self.to_s}._perform", *args)
89
+ queue.enqueue_in(time, "#{self.to_s}._perform", *serialized(args))
90
90
  end
91
91
 
92
92
  def self.restart_in(time, remaining_retries, *args)
93
- queue.enqueue_retry_in(time, "#{self.to_s}._perform", remaining_retries, *args)
93
+ queue.enqueue_retry_in(time, "#{self.to_s}._perform", remaining_retries, *serialized(args))
94
94
  end
95
95
 
96
96
  def self.do(*args)
@@ -102,13 +102,13 @@ module QueueClassicPlus
102
102
  def self._perform(*args)
103
103
  Metrics.timing("qu_perform_time", source: librato_key) do
104
104
  if skip_transaction
105
- perform(*args)
105
+ perform(*deserialized(args))
106
106
  else
107
107
  transaction do
108
108
  # .to_i defaults to 0, which means no timeout in postgres
109
109
  timeout = ENV['POSTGRES_STATEMENT_TIMEOUT'].to_i * 1000
110
110
  execute "SET LOCAL statement_timeout = #{timeout}"
111
- perform(*args)
111
+ perform(*deserialized(args))
112
112
  end
113
113
  end
114
114
  end
@@ -119,10 +119,10 @@ module QueueClassicPlus
119
119
  end
120
120
 
121
121
  def self.transaction(options = {}, &block)
122
- if defined?(ActiveRecord)
122
+ if defined?(ActiveRecord) && ActiveRecord::Base.connected?
123
123
  # If ActiveRecord is loaded, we use it's own transaction mechanisn since
124
124
  # it has slightly different semanctics for rollback.
125
- ActiveRecord::Base.transaction(options, &block)
125
+ ActiveRecord::Base.transaction(**options, &block)
126
126
  else
127
127
  begin
128
128
  execute "BEGIN"
@@ -142,7 +142,26 @@ module QueueClassicPlus
142
142
  execute q
143
143
  end
144
144
 
145
+ protected
146
+
147
+ def self.serialized(args)
148
+ if defined?(Rails)
149
+ ActiveJob::Arguments.serialize(args)
150
+ else
151
+ args
152
+ end
153
+ end
154
+
155
+ def self.deserialized(args)
156
+ if defined?(Rails)
157
+ ActiveJob::Arguments.deserialize(args)
158
+ else
159
+ args
160
+ end
161
+ end
162
+
145
163
  private
164
+
146
165
  def self.execute(sql, *args)
147
166
  QC.default_conn_adapter.execute(sql, *args)
148
167
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QueueClassicDatadog
4
+ def _perform(*args)
5
+ Datadog.tracer.trace('qc.job', service_name: 'qc.job', resource: "#{name}#perform") do |_|
6
+ super
7
+ end
8
+ end
9
+
10
+ QueueClassicPlus::Base.singleton_class.send(:prepend, QueueClassicDatadog)
11
+ end
@@ -1,30 +1,29 @@
1
1
  require 'new_relic/agent/method_tracer'
2
2
 
3
- QueueClassicPlus::Base.class_eval do
4
- class << self
5
- include NewRelic::Agent::Instrumentation::ControllerInstrumentation
3
+ module QueueClassicNewRelic
4
+ include NewRelic::Agent::Instrumentation::ControllerInstrumentation
6
5
 
7
- def new_relic_key
8
- "Custom/QueueClassicPlus/#{librato_key}"
9
- end
6
+ def new_relic_key
7
+ "Custom/QueueClassicPlus/#{librato_key}"
8
+ end
10
9
 
11
- def _perform_with_new_relic(*args)
12
- opts = {
13
- name: 'perform',
14
- class_name: self.name,
15
- category: 'OtherTransaction/QueueClassicPlus',
16
- }
10
+ def _perform(*args)
11
+ opts = {
12
+ name: 'perform',
13
+ class_name: self.name,
14
+ category: 'OtherTransaction/QueueClassicPlus',
15
+ }
17
16
 
18
- perform_action_with_newrelic_trace(opts) do
19
- if NewRelic::Agent.config[:'queue_classic_plus.capture_params']
20
- NewRelic::Agent.add_custom_parameters(job_arguments: args)
21
- end
22
- _perform_without_new_relic *args
17
+ perform_action_with_newrelic_trace(opts) do
18
+ if NewRelic::Agent.config[:'queue_classic_plus.capture_params']
19
+ NewRelic::Agent.add_custom_parameters(job_arguments: args)
23
20
  end
24
- end
25
21
 
26
- alias_method_chain :_perform, :new_relic
22
+ super
23
+ end
27
24
  end
25
+
26
+ QueueClassicPlus::Base.singleton_class.send(:prepend, QueueClassicNewRelic)
28
27
  end
29
28
 
30
29
  QueueClassicPlus::CustomWorker.class_eval do
@@ -3,7 +3,7 @@ module QC
3
3
 
4
4
  def enqueue_retry_in(seconds, method, remaining_retries, *args)
5
5
  QC.log_yield(:measure => 'queue.enqueue') do
6
- s = "INSERT INTO #{TABLE_NAME} (q_name, method, args, scheduled_at, remaining_retries)
6
+ s = "INSERT INTO #{QC.table_name} (q_name, method, args, scheduled_at, remaining_retries)
7
7
  VALUES ($1, $2, $3, now() + interval '#{seconds.to_i} seconds', $4)"
8
8
 
9
9
  conn_adapter.execute(s, name, method, JSON.dump(args), remaining_retries)
@@ -12,16 +12,36 @@ module QC
12
12
 
13
13
  def lock
14
14
  QC.log_yield(:measure => 'queue.lock') do
15
- s = "SELECT * FROM lock_head($1, $2)"
16
- if r = conn_adapter.execute(s, name, top_bound)
15
+ s = <<~SQL
16
+ WITH selected_job AS (
17
+ SELECT id
18
+ FROM queue_classic_jobs
19
+ WHERE
20
+ locked_at IS NULL AND
21
+ q_name = $1 AND
22
+ scheduled_at <= now()
23
+ LIMIT 1
24
+ FOR NO KEY UPDATE SKIP LOCKED
25
+ )
26
+ UPDATE queue_classic_jobs
27
+ SET
28
+ locked_at = now(),
29
+ locked_by = pg_backend_pid()
30
+ FROM selected_job
31
+ WHERE queue_classic_jobs.id = selected_job.id
32
+ RETURNING *
33
+ SQL
34
+
35
+ if r = conn_adapter.execute(s, name)
17
36
  {}.tap do |job|
18
37
  job[:id] = r["id"]
19
38
  job[:q_name] = r["q_name"]
20
39
  job[:method] = r["method"]
21
40
  job[:args] = JSON.parse(r["args"])
22
- job[:remaining_retries] = r["remaining_retries"]
41
+ job[:remaining_retries] = r["remaining_retries"]&.to_s
23
42
  if r["scheduled_at"]
24
- job[:scheduled_at] = Time.parse(r["scheduled_at"])
43
+ # ActiveSupport may cast time strings to Time
44
+ job[:scheduled_at] = r["scheduled_at"].kind_of?(Time) ? r["scheduled_at"] : Time.parse(r["scheduled_at"])
25
45
  ttl = Integer((Time.now - job[:scheduled_at]) * 1000)
26
46
  QC.measure("time-to-lock=#{ttl}ms source=#{name}")
27
47
  end
@@ -3,10 +3,15 @@ namespace :qc_plus do
3
3
  task :work => :environment do
4
4
  puts "Starting up worker for queue #{ENV['QUEUE']}"
5
5
 
6
- if defined? Raven
6
+ # ActiveRecord::RecordNotFound is ignored by Sentry by default,
7
+ # which shouldn't happen in background jobs.
8
+ if defined?(Sentry)
9
+ Sentry.init do |config|
10
+ config.excluded_exceptions = []
11
+ config.background_worker_threads = 0 if Gem::Version.new(Sentry::VERSION) >= Gem::Version.new('4.1.0')
12
+ end
13
+ elsif defined?(Raven)
7
14
  Raven.configure do |config|
8
- # ActiveRecord::RecordNotFound is ignored by Raven by default,
9
- # which shouldn't happen in background jobs.
10
15
  config.excluded_exceptions = []
11
16
  end
12
17
  end
@@ -1,3 +1,3 @@
1
1
  module QueueClassicPlus
2
- VERSION = "1.0.1"
2
+ VERSION = '4.0.0.alpha10'.freeze
3
3
  end
@@ -25,12 +25,14 @@ module QueueClassicPlus
25
25
  end
26
26
 
27
27
  @failed_job = job
28
+ @raw_args = job[:args]
29
+ @failed_job_args = failed_job_class ? failed_job_class.deserialized(@raw_args) : @raw_args
28
30
 
29
31
  if force_retry && !(failed_job_class.respond_to?(:disable_retries) && failed_job_class.disable_retries)
30
32
  Metrics.increment("qc.force_retry", source: @q_name)
31
33
  retry_with_remaining(e)
32
34
  # The mailers doesn't have a retries_on?
33
- elsif failed_job_class && failed_job_class.respond_to?(:retries_on?) && failed_job_class.retries_on?(e)
35
+ elsif failed_job_class.respond_to?(:retries_on?) && failed_job_class.retries_on?(e)
34
36
  Metrics.increment("qc.retry", source: @q_name)
35
37
  retry_with_remaining(e)
36
38
  else
@@ -44,7 +46,7 @@ module QueueClassicPlus
44
46
 
45
47
  def retry_with_remaining(e)
46
48
  if remaining_retries > 0
47
- failed_job_class.restart_in(backoff, remaining_retries - 1, *@failed_job[:args])
49
+ failed_job_class.restart_in(backoff, remaining_retries - 1, *@failed_job_args)
48
50
  else
49
51
  enqueue_failed(e)
50
52
  end
@@ -59,11 +61,9 @@ module QueueClassicPlus
59
61
  end
60
62
 
61
63
  def failed_job_class
62
- begin
63
- Object.const_get(@failed_job[:method].split('.')[0])
64
- rescue NameError
65
- nil
66
- end
64
+ Object.const_get(@failed_job[:method].split('.')[0])
65
+ rescue NameError
66
+ nil
67
67
  end
68
68
 
69
69
  def backoff
@@ -77,9 +77,10 @@ module QueueClassicPlus
77
77
  end
78
78
 
79
79
  def enqueue_failed(e)
80
- sql = "INSERT INTO #{QC::TABLE_NAME} (q_name, method, args, last_error) VALUES ('failed_jobs', $1, $2, $3)"
80
+ sql = "INSERT INTO #{QC.table_name} (q_name, method, args, last_error) VALUES ('failed_jobs', $1, $2, $3)"
81
81
  last_error = e.backtrace ? ([e.message] + e.backtrace ).join("\n") : e.message
82
- QC.default_conn_adapter.execute sql, @failed_job[:method], JSON.dump(@failed_job[:args]), last_error
82
+
83
+ QC.default_conn_adapter.execute sql, @failed_job[:method], JSON.dump(@raw_args), last_error
83
84
 
84
85
  QueueClassicPlus.exception_handler.call(e, @failed_job)
85
86
  Metrics.increment("qc.errors", source: @q_name)
@@ -14,13 +14,13 @@ module QueueClassicPlus
14
14
  require 'queue_classic_plus/railtie' if defined?(Rails)
15
15
 
16
16
  def self.migrate(c = QC::default_conn_adapter.connection)
17
- conn = QC::ConnAdapter.new(c)
17
+ conn = QC::ConnAdapter.new(connection: c)
18
18
  conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN last_error TEXT")
19
19
  conn.execute("ALTER TABLE queue_classic_jobs ADD COLUMN remaining_retries INTEGER")
20
20
  end
21
21
 
22
22
  def self.demigrate(c = QC::default_conn_adapter.connection)
23
- conn = QC::ConnAdapter.new(c)
23
+ conn = QC::ConnAdapter.new(connection: c)
24
24
  conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN last_error")
25
25
  conn.execute("ALTER TABLE queue_classic_jobs DROP COLUMN remaining_retries")
26
26
  end
@@ -18,7 +18,13 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "queue_classic", ">= 3.1.0"
22
- spec.add_development_dependency "bundler", "~> 1.6"
21
+ spec.add_dependency "queue_classic", "4.0.0.pre.alpha1"
22
+ if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ else
25
+ spec.add_development_dependency "bundler", "~> 2.0"
26
+ end
23
27
  spec.add_development_dependency "rake"
28
+ spec.add_development_dependency "activerecord", "~> 6.0"
29
+ spec.add_development_dependency "activejob"
24
30
  end
data/spec/base_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+ require 'active_record'
1
3
 
2
4
  describe QueueClassicPlus::Base do
3
5
  context "A child of QueueClassicPlus::Base" do
@@ -12,7 +14,19 @@ describe QueueClassicPlus::Base do
12
14
  it "does not allow multiple enqueues" do
13
15
  subject.do
14
16
  subject.do
15
- subject.should have_queue_size_of(1)
17
+ expect(subject).to have_queue_size_of(1)
18
+ end
19
+
20
+ it "checks for an existing job using the same serializing as job enqueuing" do
21
+ # simulate a case where obj#to_json and JSON.dump(obj) do not match
22
+ require 'active_support/core_ext/date_time'
23
+ require 'active_support/json'
24
+ ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
25
+
26
+ date = DateTime.new(2020, 11, 3)
27
+ subject.do(date)
28
+ subject.do(date)
29
+ expect(subject).to have_queue_size_of(1)
16
30
  end
17
31
 
18
32
  it "does allow multiple enqueues if something got locked for too long" do
@@ -20,7 +34,7 @@ describe QueueClassicPlus::Base do
20
34
  one_day_ago = Time.now - 60*60*24
21
35
  execute "UPDATE queue_classic_jobs SET locked_at = '#{one_day_ago}' WHERE q_name = 'test'"
22
36
  subject.do
23
- subject.should have_queue_size_of(2)
37
+ expect(subject).to have_queue_size_of(2)
24
38
  end
25
39
  end
26
40
 
@@ -39,13 +53,15 @@ describe QueueClassicPlus::Base do
39
53
  end
40
54
 
41
55
  it "calls perform in a transaction" do
42
- QueueClassicPlus::Base.should_receive(:transaction).and_call_original
56
+ expect(QueueClassicPlus::Base).to receive(:transaction).and_call_original
57
+
43
58
  subject._perform
44
59
  end
45
60
 
46
61
  it "measures the time" do
47
- QueueClassicPlus::Metrics.should_receive(:timing).with("qu_perform_time", {source: "funky.name"}).and_call_original
48
- subject._perform
62
+ expect(QueueClassicPlus::Metrics).to receive(:timing).with("qu_perform_time", {source: "funky.name"}).and_call_original
63
+
64
+ subject._perform
49
65
  end
50
66
  end
51
67
 
@@ -61,7 +77,8 @@ describe QueueClassicPlus::Base do
61
77
  end
62
78
 
63
79
  it "calls perform outside of a transaction" do
64
- QueueClassicPlus::Base.should_not_receive(:transaction)
80
+ expect(QueueClassicPlus::Base).to_not receive(:transaction)
81
+
65
82
  subject._perform
66
83
  end
67
84
  end
@@ -79,15 +96,15 @@ describe QueueClassicPlus::Base do
79
96
  end
80
97
 
81
98
  it "retries on specified exception" do
82
- subject.retries_on?(SomeException.new).should be(true)
99
+ expect(subject.retries_on?(SomeException.new)).to be(true)
83
100
  end
84
101
 
85
102
  it "does not retry on unspecified exceptions" do
86
- subject.retries_on?(RuntimeError).should be(false)
103
+ expect(subject.retries_on?(RuntimeError)).to be(false)
87
104
  end
88
105
 
89
106
  it "sets max retries" do
90
- subject.max_retries.should == 5
107
+ expect(subject.max_retries).to eq(5)
91
108
  end
92
109
  end
93
110
 
@@ -104,16 +121,16 @@ describe QueueClassicPlus::Base do
104
121
  end
105
122
 
106
123
  it "retries on all specified exceptions" do
107
- subject.retries_on?(SomeException.new).should be(true)
108
- subject.retries_on?(SomeOtherException.new).should be(true)
124
+ expect(subject.retries_on?(SomeException.new)).to be(true)
125
+ expect(subject.retries_on?(SomeOtherException.new)).to be(true)
109
126
  end
110
127
 
111
128
  it "does not retry on unspecified exceptions" do
112
- subject.retries_on?(RuntimeError).should be(false)
129
+ expect(subject.retries_on?(RuntimeError)).to be(false)
113
130
  end
114
131
 
115
132
  it "sets max retries" do
116
- subject.max_retries.should == 5
133
+ expect(subject.max_retries).to eq(5)
117
134
  end
118
135
  end
119
136
 
@@ -133,23 +150,73 @@ describe QueueClassicPlus::Base do
133
150
  end
134
151
 
135
152
  it "retries on a subclass of a specified exception" do
136
- subject.retries_on?(ServiceReallyUnavailable.new).should be(true)
153
+ expect(subject.retries_on?(ServiceReallyUnavailable.new)).to be(true)
137
154
  end
138
155
 
139
156
  it "does not retry on unspecified exceptions" do
140
- subject.retries_on?(RuntimeError).should be(false)
157
+ expect(subject.retries_on?(RuntimeError)).to be(false)
141
158
  end
142
159
 
143
160
  it "sets max retries" do
144
- subject.max_retries.should == 5
161
+ expect(subject.max_retries).to eq(5)
162
+ end
163
+ end
164
+
165
+ context "with Rails defined", rails: true do
166
+ subject do
167
+ Class.new(QueueClassicPlus::Base) do
168
+ @queue = :test
169
+
170
+ def self.perform(foo, bar)
171
+ end
172
+ end
173
+ end
174
+
175
+ it "serializes parameters when enqueuing a job" do
176
+ expect(ActiveJob::Arguments).to receive(:serialize).with([42, true])
177
+
178
+ subject.do(42, true)
179
+ end
180
+
181
+ it "deserializes parameters when performing an enqueued job" do
182
+ expect(ActiveJob::Arguments).to receive(:deserialize).with([42, true]) { [42, true] }
183
+
184
+ subject._perform(42, true)
145
185
  end
146
186
  end
147
187
  end
148
188
 
149
189
  describe ".librato_key" do
150
190
  it "removes unsupported caracter from the classname" do
151
- Jobs::Tests::TestJob.librato_key.should == 'jobs.tests.test_job'
191
+ expect(Jobs::Tests::TestJob.librato_key).to eq('jobs.tests.test_job')
152
192
  end
153
193
  end
154
- end
155
194
 
195
+ context 'with ActiveRecord' do
196
+ before do
197
+ @old_conn_adapter = QC.default_conn_adapter
198
+ @activerecord_conn = ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])
199
+ QC.default_conn_adapter = QC::ConnAdapter.new(
200
+ connection: ActiveRecord::Base.connection.raw_connection
201
+ )
202
+ end
203
+
204
+ after do
205
+ @activerecord_conn.disconnect!
206
+ QC.default_conn_adapter = @old_conn_adapter
207
+ end
208
+
209
+ subject do
210
+ Class.new(QueueClassicPlus::Base) do
211
+ @queue = :test
212
+
213
+ def self.perform(foo, bar)
214
+ end
215
+ end
216
+ end
217
+
218
+ it 'works' do
219
+ expect { subject._perform(1, 2) }.not_to raise_error
220
+ end
221
+ end
222
+ 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
@@ -4,6 +4,6 @@ module QcHelpers
4
4
  end
5
5
 
6
6
  def find_job(id)
7
- execute("SELECT * FROM #{QC::TABLE_NAME} WHERE id = $1", id)
7
+ execute("SELECT * FROM #{QC.table_name} WHERE id = $1", id)
8
8
  end
9
9
  end
@@ -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
@@ -1,12 +1,23 @@
1
1
  require 'spec_helper'
2
+ require 'active_record'
2
3
 
3
4
  describe QC do
4
-
5
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
6
14
 
7
- context "lock" do
15
+ after do
16
+ @activerecord_conn.disconnect!
17
+ QC.default_conn_adapter = @old_conn_adapter
18
+ end
8
19
 
9
- it "should lock the job with remaining_retries" do
20
+ it "locks the job with remaining_retries" do
10
21
  QC.enqueue_retry_in(1, "puts", 5, 2)
11
22
  sleep 1
12
23
  job = QC.lock
@@ -18,6 +29,15 @@ describe QC do
18
29
  end
19
30
  end
20
31
 
21
- end
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
22
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
23
43
  end
data/spec/sample_jobs.rb CHANGED
@@ -14,7 +14,7 @@ module Jobs
14
14
  @queue = :low
15
15
  retry! on: SomeException, max: 5
16
16
 
17
- def self.perform should_raise
17
+ def self.perform(should_raise)
18
18
  raise SomeException if should_raise
19
19
  end
20
20
  end
@@ -27,7 +27,7 @@ module Jobs
27
27
 
28
28
  @queue = :low
29
29
 
30
- def self.perform should_raise
30
+ def self.perform(should_raise)
31
31
  raise Custom if should_raise
32
32
  end
33
33
  end
@@ -37,7 +37,7 @@ module Jobs
37
37
  @queue = :low
38
38
  retry! on: SomeException, max: 1
39
39
 
40
- def self.perform should_raise
40
+ def self.perform(should_raise)
41
41
  raise SomeException if should_raise
42
42
  end
43
43
  end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,21 @@
1
+ require 'simplecov'
2
+
3
+ SimpleCov.start do
4
+ add_filter(%r/^\/spec\//)
5
+ enable_coverage(:branch)
6
+ end
7
+
1
8
  require 'queue_classic_plus'
2
9
  require 'pg'
3
10
  require 'timecop'
4
11
  require 'queue_classic_matchers'
5
12
  require_relative './sample_jobs'
6
13
  require_relative './helpers'
14
+ require 'byebug'
7
15
  require 'pry'
16
+ require 'ddtrace'
8
17
 
18
+ ENV["QC_RAILS_DATABASE"] ||= "false" # test on QC::ConnAdapter by default
9
19
  ENV["DATABASE_URL"] ||= "postgres:///queue_classic_plus_test"
10
20
 
11
21
  RSpec.configure do |config|
@@ -20,5 +30,14 @@ RSpec.configure do |config|
20
30
 
21
31
  config.before(:each) do
22
32
  QC.default_conn_adapter.execute "TRUNCATE queue_classic_jobs;"
33
+ # Reset the default (memoized) queue instance between specs
34
+ QC.default_queue = nil
35
+ end
36
+
37
+ config.before(:each, rails: true) do
38
+ require 'active_job'
39
+ require 'active_job/arguments'
40
+
41
+ stub_const('Rails', Struct.new(:logger).new(Logger.new(STDOUT)))
23
42
  end
24
43
  end
data/spec/worker_spec.rb CHANGED
@@ -9,22 +9,42 @@ 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.should == 0
12
+ expect(failed_queue.count).to eq(0)
13
13
  worker.work
14
- failed_queue.count.should == 1
14
+ expect(failed_queue.count).to eq(1)
15
15
  job = failed_queue.lock
16
- job[:method].should == "Kerklfadsjflaksj"
17
- job[:args].should == [1, 2, 3]
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'].should_not be_nil
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.should == 0
25
+ expect(failed_queue.count).to eq(0)
26
26
  worker.work
27
- failed_queue.count.should == 1
27
+ expect(failed_queue.count).to eq(1)
28
+ end
29
+
30
+ context 'when Rails is defined', rails: true do
31
+ let(:job_type) { Jobs::Tests::TestJobNoRetry }
32
+ let(:queue) { job_type.queue }
33
+
34
+ it 'properly serializes arguments for jobs in the failed queue' do
35
+ job_type.enqueue_perform(:raise)
36
+ expect(failed_queue.count).to eq(0)
37
+ worker.work
38
+
39
+ expect(failed_queue.count).to eq(1)
40
+ job = QueueClassicMatchers::QueueClassicRspec.find_by_args(
41
+ 'failed_jobs',
42
+ 'Jobs::Tests::TestJobNoRetry._perform',
43
+ [:raise]).first
44
+
45
+ expect(job).to_not be_nil
46
+ expect(job['last_error']).to_not be_nil
47
+ end
28
48
  end
29
49
  end
30
50
 
@@ -42,28 +62,62 @@ describe QueueClassicPlus::CustomWorker do
42
62
  job_type.enqueue_perform(true)
43
63
  end.to change_queue_size_of(job_type).by(1)
44
64
 
45
- Jobs::Tests::LockedTestJob.should have_queue_size_of(1)
46
- failed_queue.count.should == 0
47
- QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].should be_nil
65
+ expect(Jobs::Tests::LockedTestJob).to have_queue_size_of(1)
66
+ expect(failed_queue.count).to eq(0)
67
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to be_nil
48
68
 
49
- QueueClassicPlus::Metrics.should_receive(:increment).with('qc.retry', source: nil )
69
+ expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil )
50
70
 
51
71
  Timecop.freeze do
52
72
  worker.work
53
73
 
54
- failed_queue.count.should == 0 # not enqueued on Failed
55
- QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].should eq "4"
56
- Jobs::Tests::LockedTestJob.should have_scheduled(true).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
74
+ expect(failed_queue.count).to eq(0) # not enqueued on Failed
75
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to eq "4"
76
+ expect(Jobs::Tests::LockedTestJob).to have_scheduled(true).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
57
77
  end
58
78
 
59
79
  Timecop.freeze(Time.now + (described_class::BACKOFF_WIDTH * 2)) do
60
80
  # the job should be re-enqueued with a decremented retry count
61
81
  jobs = QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true])
62
- jobs.size.should == 1
82
+ expect(jobs.size).to eq(1)
63
83
  job = jobs.first
64
- job['remaining_retries'].to_i.should == job_type.max_retries - 1
65
- job['locked_by'].should be_nil
66
- job['locked_at'].should be_nil
84
+ expect(job['remaining_retries'].to_i).to eq(job_type.max_retries - 1)
85
+ expect(job['locked_by']).to be_nil
86
+ expect(job['locked_at']).to be_nil
87
+ end
88
+ end
89
+
90
+ context 'when Rails is defined', rails: true do
91
+ it 'retries' do
92
+ expect do
93
+ job_type.enqueue_perform(:foo)
94
+ end.to change_queue_size_of(job_type).by(1)
95
+
96
+ expect(Jobs::Tests::LockedTestJob).to have_queue_size_of(1)
97
+ expect(failed_queue.count).to eq(0)
98
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [:foo]).first['remaining_retries']).to be_nil
99
+
100
+ expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil).twice
101
+
102
+ Timecop.freeze do
103
+ worker.work
104
+
105
+ expect(failed_queue.count).to eq(0) # not enqueued on Failed
106
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [:foo]).first['remaining_retries']).to eq "4"
107
+ expect(Jobs::Tests::LockedTestJob).to have_scheduled(:foo).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
108
+ end
109
+
110
+ Timecop.freeze(Time.now + (described_class::BACKOFF_WIDTH * 2)) do
111
+ # the job should be re-enqueued with a decremented retry count
112
+ jobs = QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [:foo])
113
+ expect(jobs.size).to eq(1)
114
+ job = jobs.first
115
+ expect(job['remaining_retries'].to_i).to eq(job_type.max_retries - 1)
116
+ expect(job['locked_by']).to be_nil
117
+ expect(job['locked_at']).to be_nil
118
+ end
119
+
120
+ worker.work
67
121
  end
68
122
  end
69
123
 
@@ -71,11 +125,11 @@ describe QueueClassicPlus::CustomWorker do
71
125
  before { Jobs::Tests::ConnectionReapedTestJob.enqueue_perform }
72
126
 
73
127
  it 'retries' do
74
- QueueClassicPlus::Metrics.should_receive(:increment).with('qc.force_retry', source: nil )
128
+ expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.force_retry', source: nil )
75
129
  Timecop.freeze do
76
130
  worker.work
77
131
  expect(failed_queue.count).to eq 0
78
- QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::ConnectionReapedTestJob._perform', []).first['remaining_retries'].should eq "4"
132
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::ConnectionReapedTestJob._perform', []).first['remaining_retries']).to eq "4"
79
133
  end
80
134
  end
81
135
 
@@ -92,11 +146,11 @@ describe QueueClassicPlus::CustomWorker do
92
146
  before { Jobs::Tests::TestJob.enqueue_perform(true) }
93
147
 
94
148
  it 'retries' do
95
- QueueClassicPlus::Metrics.should_receive(:increment).with('qc.retry', source: nil )
149
+ expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil )
96
150
  Timecop.freeze do
97
151
  worker.work
98
152
  expect(failed_queue.count).to eq 0
99
- QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::TestJob._perform', [true]).first['remaining_retries'].should eq "0"
153
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::TestJob._perform', [true]).first['remaining_retries']).to eq "0"
100
154
  end
101
155
  end
102
156
  end
@@ -126,16 +180,16 @@ describe QueueClassicPlus::CustomWorker do
126
180
  job_type.enqueue_perform(true)
127
181
  end.to change_queue_size_of(job_type).by(1)
128
182
 
129
- Jobs::Tests::LockedTestJob.should have_queue_size_of(1)
130
- failed_queue.count.should == 0
131
- QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].should be_nil
183
+ expect(Jobs::Tests::LockedTestJob).to have_queue_size_of(1)
184
+ expect(failed_queue.count).to eq(0)
185
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to be_nil
132
186
 
133
187
  Timecop.freeze do
134
188
  worker.work
135
189
 
136
- QueueClassicMatchers::QueueClassicRspec.find_by_args('failed_jobs', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].should be_nil
137
- failed_queue.count.should == 1 # not enqueued on Failed
138
- Jobs::Tests::LockedTestJob.should_not have_scheduled(true).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
190
+ expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('failed_jobs', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries']).to be_nil
191
+ expect(failed_queue.count).to eq(1) # not enqueued on Failed
192
+ expect(Jobs::Tests::LockedTestJob).to_not have_scheduled(true).at(Time.now + described_class::BACKOFF_WIDTH) # should have scheduled a retry for later
139
193
  end
140
194
  end
141
195
  end
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: 1.0.1
4
+ version: 4.0.0.alpha10
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: 2018-05-14 00:00:00.000000000 Z
13
+ date: 2022-01-03 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: 3.1.0
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: 3.1.0
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: '1.6'
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: '1.6'
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,10 @@ 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
- - ".rvmrc"
69
- - ".travis.yml"
70
98
  - Gemfile
71
99
  - Guardfile
72
100
  - LICENSE.txt
@@ -74,6 +102,7 @@ files:
74
102
  - Rakefile
75
103
  - lib/queue_classic_plus.rb
76
104
  - lib/queue_classic_plus/base.rb
105
+ - lib/queue_classic_plus/datadog.rb
77
106
  - lib/queue_classic_plus/inflector.rb
78
107
  - lib/queue_classic_plus/inheritable_attr.rb
79
108
  - lib/queue_classic_plus/metrics.rb
@@ -89,8 +118,10 @@ files:
89
118
  - lib/rails/generators/qc_plus_job/templates/job_spec.rb.erb
90
119
  - queue_classic_plus.gemspec
91
120
  - spec/base_spec.rb
121
+ - spec/datadog_spec.rb
92
122
  - spec/helpers.rb
93
123
  - spec/inflector_spec.rb
124
+ - spec/new_relic_spec.rb
94
125
  - spec/queue_classic/queue_spec.rb
95
126
  - spec/sample_jobs.rb
96
127
  - spec/spec_helper.rb
@@ -111,19 +142,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
142
  version: '0'
112
143
  required_rubygems_version: !ruby/object:Gem::Requirement
113
144
  requirements:
114
- - - ">="
145
+ - - ">"
115
146
  - !ruby/object:Gem::Version
116
- version: '0'
147
+ version: 1.3.1
117
148
  requirements: []
118
- rubyforge_project:
119
- rubygems_version: 2.6.13
149
+ rubygems_version: 3.2.32
120
150
  signing_key:
121
151
  specification_version: 4
122
152
  summary: Useful extras for Queue Classic
123
153
  test_files:
124
154
  - spec/base_spec.rb
155
+ - spec/datadog_spec.rb
125
156
  - spec/helpers.rb
126
157
  - spec/inflector_spec.rb
158
+ - spec/new_relic_spec.rb
127
159
  - spec/queue_classic/queue_spec.rb
128
160
  - spec/sample_jobs.rb
129
161
  - spec/spec_helper.rb
data/.rvmrc DELETED
@@ -1 +0,0 @@
1
- rvm use 2.1.3@queue_classic_plus --create
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: ruby
2
- before_install:
3
- - gem update bundler
4
- install: bundle install --without development
5
- before_script:
6
- - psql -c 'create database queue_classic_plus_test;' -U postgres
7
-
8
- rvm:
9
- - 2.0.0
10
- - 2.1.5
11
- - 2.2.0
12
- - 2.3.1