queue_classic_plus 1.1.0 → 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 +4 -4
- data/.circleci/config.yml +67 -0
- data/.github/dependabot.yml +8 -0
- data/.gitignore +2 -0
- data/Gemfile +2 -0
- data/README.md +8 -2
- data/lib/queue_classic_plus/base.rb +26 -7
- data/lib/queue_classic_plus/datadog.rb +11 -0
- data/lib/queue_classic_plus/queue_classic/queue.rb +25 -5
- data/lib/queue_classic_plus/tasks/work.rake +8 -3
- data/lib/queue_classic_plus/version.rb +1 -1
- data/lib/queue_classic_plus/worker.rb +4 -3
- data/lib/queue_classic_plus.rb +2 -2
- data/queue_classic_plus.gemspec +3 -1
- data/spec/base_spec.rb +59 -17
- data/spec/datadog_spec.rb +18 -0
- data/spec/helpers.rb +1 -1
- data/spec/queue_classic/queue_spec.rb +24 -4
- data/spec/sample_jobs.rb +3 -3
- data/spec/spec_helper.rb +5 -0
- data/spec/worker_spec.rb +67 -28
- metadata +42 -11
- data/.travis.yml +0 -14
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 69af5e1cbbcc08c7cd0acad4c0f06e112a9fff09756a06c9ae2ffd80a71ab39a
|
|
4
|
+
data.tar.gz: cd3cc486050b9de66397099f81e0277aac83f5469bb925456527b331dec85a6a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8d3980cb5a576ff5681812a2e5d7497c35ff98dc84934778f4dd3c867643e10e9d87a38499bad6850cc72d1c4cd519a91a2509011f8ad916e78b10be3c2e076e
|
|
7
|
+
data.tar.gz: c31d0baa284b76731b268e29ab21b3ae0e679f7404345d3b449fb755a34df11100d6f6790a6f9e0dfb373ed908a8fa365575d88184f96d28a079270be5e67605
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
|
|
3
|
+
jobs:
|
|
4
|
+
test:
|
|
5
|
+
docker:
|
|
6
|
+
- image: circleci/ruby:2.7.4-node
|
|
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: circleci/ruby:2.7.4
|
|
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
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# QueueClassicPlus
|
|
2
2
|
|
|
3
|
-
[](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
|
-
|
|
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 )
|
|
@@ -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
|
|
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,7 +119,7 @@ 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
125
|
ActiveRecord::Base.transaction(options, &block)
|
|
@@ -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
|
|
@@ -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 #{
|
|
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 =
|
|
16
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
@@ -25,6 +25,7 @@ module QueueClassicPlus
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
@failed_job = job
|
|
28
|
+
@failed_job_args = failed_job_class ? failed_job_class.deserialized(job[:args]) : job[:args]
|
|
28
29
|
|
|
29
30
|
if force_retry && !(failed_job_class.respond_to?(:disable_retries) && failed_job_class.disable_retries)
|
|
30
31
|
Metrics.increment("qc.force_retry", source: @q_name)
|
|
@@ -44,7 +45,7 @@ module QueueClassicPlus
|
|
|
44
45
|
|
|
45
46
|
def retry_with_remaining(e)
|
|
46
47
|
if remaining_retries > 0
|
|
47
|
-
failed_job_class.restart_in(backoff, remaining_retries - 1, *@
|
|
48
|
+
failed_job_class.restart_in(backoff, remaining_retries - 1, *@failed_job_args)
|
|
48
49
|
else
|
|
49
50
|
enqueue_failed(e)
|
|
50
51
|
end
|
|
@@ -77,9 +78,9 @@ module QueueClassicPlus
|
|
|
77
78
|
end
|
|
78
79
|
|
|
79
80
|
def enqueue_failed(e)
|
|
80
|
-
sql = "INSERT INTO #{QC
|
|
81
|
+
sql = "INSERT INTO #{QC.table_name} (q_name, method, args, last_error) VALUES ('failed_jobs', $1, $2, $3)"
|
|
81
82
|
last_error = e.backtrace ? ([e.message] + e.backtrace ).join("\n") : e.message
|
|
82
|
-
QC.default_conn_adapter.execute sql, @failed_job[:method], JSON.dump(@
|
|
83
|
+
QC.default_conn_adapter.execute sql, @failed_job[:method], JSON.dump(@failed_job_args), last_error
|
|
83
84
|
|
|
84
85
|
QueueClassicPlus.exception_handler.call(e, @failed_job)
|
|
85
86
|
Metrics.increment("qc.errors", source: @q_name)
|
data/lib/queue_classic_plus.rb
CHANGED
|
@@ -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
|
data/queue_classic_plus.gemspec
CHANGED
|
@@ -18,11 +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", "
|
|
21
|
+
spec.add_dependency "queue_classic", "4.0.0.pre.alpha1"
|
|
22
22
|
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3.0')
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.6"
|
|
24
24
|
else
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 2.0"
|
|
26
26
|
end
|
|
27
27
|
spec.add_development_dependency "rake"
|
|
28
|
+
spec.add_development_dependency "activerecord", "~> 6.0"
|
|
29
|
+
spec.add_development_dependency "activejob"
|
|
28
30
|
end
|
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
|
@@ -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
|
-
|
|
15
|
+
after do
|
|
16
|
+
@activerecord_conn.disconnect!
|
|
17
|
+
QC.default_conn_adapter = @old_conn_adapter
|
|
18
|
+
end
|
|
8
19
|
|
|
9
|
-
it "
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
@@ -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,28 +42,67 @@ 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
48
|
|
|
49
|
-
QueueClassicPlus::Metrics.
|
|
49
|
+
expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil )
|
|
50
50
|
|
|
51
51
|
Timecop.freeze do
|
|
52
52
|
worker.work
|
|
53
53
|
|
|
54
|
-
failed_queue.count.
|
|
55
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].
|
|
56
|
-
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
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
Timecop.freeze(Time.now + (described_class::BACKOFF_WIDTH * 2)) do
|
|
60
60
|
# the job should be re-enqueued with a decremented retry count
|
|
61
61
|
jobs = QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true])
|
|
62
|
-
jobs.size.
|
|
62
|
+
expect(jobs.size).to eq(1)
|
|
63
63
|
job = jobs.first
|
|
64
|
-
job['remaining_retries'].to_i.
|
|
65
|
-
job['locked_by'].
|
|
66
|
-
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
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'when Rails is defined' do
|
|
71
|
+
require 'active_job'
|
|
72
|
+
require 'active_job/arguments'
|
|
73
|
+
|
|
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
|
|
104
|
+
|
|
105
|
+
worker.work
|
|
67
106
|
end
|
|
68
107
|
end
|
|
69
108
|
|
|
@@ -71,11 +110,11 @@ describe QueueClassicPlus::CustomWorker do
|
|
|
71
110
|
before { Jobs::Tests::ConnectionReapedTestJob.enqueue_perform }
|
|
72
111
|
|
|
73
112
|
it 'retries' do
|
|
74
|
-
QueueClassicPlus::Metrics.
|
|
113
|
+
expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.force_retry', source: nil )
|
|
75
114
|
Timecop.freeze do
|
|
76
115
|
worker.work
|
|
77
116
|
expect(failed_queue.count).to eq 0
|
|
78
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::ConnectionReapedTestJob._perform', []).first['remaining_retries'].
|
|
117
|
+
expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::ConnectionReapedTestJob._perform', []).first['remaining_retries']).to eq "4"
|
|
79
118
|
end
|
|
80
119
|
end
|
|
81
120
|
|
|
@@ -92,11 +131,11 @@ describe QueueClassicPlus::CustomWorker do
|
|
|
92
131
|
before { Jobs::Tests::TestJob.enqueue_perform(true) }
|
|
93
132
|
|
|
94
133
|
it 'retries' do
|
|
95
|
-
QueueClassicPlus::Metrics.
|
|
134
|
+
expect(QueueClassicPlus::Metrics).to receive(:increment).with('qc.retry', source: nil )
|
|
96
135
|
Timecop.freeze do
|
|
97
136
|
worker.work
|
|
98
137
|
expect(failed_queue.count).to eq 0
|
|
99
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::TestJob._perform', [true]).first['remaining_retries'].
|
|
138
|
+
expect(QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::TestJob._perform', [true]).first['remaining_retries']).to eq "0"
|
|
100
139
|
end
|
|
101
140
|
end
|
|
102
141
|
end
|
|
@@ -126,16 +165,16 @@ describe QueueClassicPlus::CustomWorker do
|
|
|
126
165
|
job_type.enqueue_perform(true)
|
|
127
166
|
end.to change_queue_size_of(job_type).by(1)
|
|
128
167
|
|
|
129
|
-
Jobs::Tests::LockedTestJob.
|
|
130
|
-
failed_queue.count.
|
|
131
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].
|
|
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
|
|
132
171
|
|
|
133
172
|
Timecop.freeze do
|
|
134
173
|
worker.work
|
|
135
174
|
|
|
136
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('failed_jobs', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].
|
|
137
|
-
failed_queue.count.
|
|
138
|
-
Jobs::Tests::LockedTestJob.
|
|
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
|
|
139
178
|
end
|
|
140
179
|
end
|
|
141
180
|
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:
|
|
4
|
+
version: 4.0.0.alpha8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Simon Mathieu
|
|
@@ -10,22 +10,22 @@ 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
|
|
@@ -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,6 +119,7 @@ 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
|
|
94
125
|
- spec/new_relic_spec.rb
|
|
@@ -112,17 +143,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
112
143
|
version: '0'
|
|
113
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
145
|
requirements:
|
|
115
|
-
- - "
|
|
146
|
+
- - ">"
|
|
116
147
|
- !ruby/object:Gem::Version
|
|
117
|
-
version:
|
|
148
|
+
version: 1.3.1
|
|
118
149
|
requirements: []
|
|
119
|
-
|
|
120
|
-
rubygems_version: 2.7.6
|
|
150
|
+
rubygems_version: 3.1.6
|
|
121
151
|
signing_key:
|
|
122
152
|
specification_version: 4
|
|
123
153
|
summary: Useful extras for Queue Classic
|
|
124
154
|
test_files:
|
|
125
155
|
- spec/base_spec.rb
|
|
156
|
+
- spec/datadog_spec.rb
|
|
126
157
|
- spec/helpers.rb
|
|
127
158
|
- spec/inflector_spec.rb
|
|
128
159
|
- spec/new_relic_spec.rb
|
data/.travis.yml
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
language: ruby
|
|
2
|
-
services:
|
|
3
|
-
- postgresql
|
|
4
|
-
before_install:
|
|
5
|
-
- gem update bundler
|
|
6
|
-
install: bundle install --without development
|
|
7
|
-
before_script:
|
|
8
|
-
- psql -c 'create database queue_classic_plus_test;' -U postgres
|
|
9
|
-
|
|
10
|
-
rvm:
|
|
11
|
-
- 2.0.0
|
|
12
|
-
- 2.1.5
|
|
13
|
-
- 2.2.0
|
|
14
|
-
- 2.3.1
|