queue_classic_plus 1.0.1 → 4.0.0.alpha10

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