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 +5 -5
- data/.circleci/config.yml +67 -0
- data/.github/dependabot.yml +8 -0
- data/.gitignore +2 -0
- data/Gemfile +4 -1
- data/README.md +12 -2
- data/lib/queue_classic_plus/base.rb +27 -8
- data/lib/queue_classic_plus/datadog.rb +11 -0
- data/lib/queue_classic_plus/new_relic.rb +18 -19
- 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 +10 -9
- data/lib/queue_classic_plus.rb +2 -2
- data/queue_classic_plus.gemspec +8 -2
- data/spec/base_spec.rb +85 -18
- data/spec/datadog_spec.rb +18 -0
- data/spec/helpers.rb +1 -1
- data/spec/new_relic_spec.rb +26 -0
- data/spec/queue_classic/queue_spec.rb +24 -4
- data/spec/sample_jobs.rb +3 -3
- data/spec/spec_helper.rb +19 -0
- data/spec/worker_spec.rb +82 -28
- metadata +46 -14
- data/.rvmrc +0 -1
- data/.travis.yml +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 14e8dfec194b5946e629568f8fc73041f0a9f546b737ab2926446cfa0bffe854
|
4
|
+
data.tar.gz: e45cbfdd17b764c9569f554ac989e3ab03948a237265f53605aba8032be28bd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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 )
|
@@ -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
|
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
|
-
|
4
|
-
|
5
|
-
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
3
|
+
module QueueClassicNewRelic
|
4
|
+
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def new_relic_key
|
7
|
+
"Custom/QueueClassicPlus/#{librato_key}"
|
8
|
+
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
def _perform(*args)
|
11
|
+
opts = {
|
12
|
+
name: 'perform',
|
13
|
+
class_name: self.name,
|
14
|
+
category: 'OtherTransaction/QueueClassicPlus',
|
15
|
+
}
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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 #{
|
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,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
|
-
|
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, *@
|
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
|
-
|
63
|
-
|
64
|
-
|
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
|
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
|
-
|
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)
|
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,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", "
|
22
|
-
|
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.
|
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.
|
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.
|
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.
|
48
|
-
|
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.
|
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).
|
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).
|
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.
|
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).
|
108
|
-
subject.retries_on?(SomeOtherException.new).
|
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).
|
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.
|
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).
|
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).
|
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.
|
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.
|
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
@@ -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
|
-
|
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
@@ -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.
|
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
|
+
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.
|
46
|
-
failed_queue.count.
|
47
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].
|
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.
|
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.
|
55
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].
|
56
|
-
Jobs::Tests::LockedTestJob.
|
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.
|
82
|
+
expect(jobs.size).to eq(1)
|
63
83
|
job = jobs.first
|
64
|
-
job['remaining_retries'].to_i.
|
65
|
-
job['locked_by'].
|
66
|
-
job['locked_at'].
|
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.
|
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'].
|
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.
|
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'].
|
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.
|
130
|
-
failed_queue.count.
|
131
|
-
QueueClassicMatchers::QueueClassicRspec.find_by_args('low', 'Jobs::Tests::LockedTestJob._perform', [true]).first['remaining_retries'].
|
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'].
|
137
|
-
failed_queue.count.
|
138
|
-
Jobs::Tests::LockedTestJob.
|
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:
|
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:
|
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:
|
21
|
+
version: 4.0.0.pre.alpha1
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
|
-
- -
|
26
|
+
- - '='
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version:
|
28
|
+
version: 4.0.0.pre.alpha1
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: bundler
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
33
|
- - "~>"
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: '
|
35
|
+
version: '2.0'
|
36
36
|
type: :development
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: '
|
42
|
+
version: '2.0'
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: rake
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
@@ -54,6 +54,34 @@ dependencies:
|
|
54
54
|
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '0'
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: activerecord
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '6.0'
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '6.0'
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: activejob
|
73
|
+
requirement: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
type: :development
|
79
|
+
prerelease: false
|
80
|
+
version_requirements: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
57
85
|
description: ''
|
58
86
|
email:
|
59
87
|
- simon.math@gmail.com
|
@@ -63,10 +91,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:
|
147
|
+
version: 1.3.1
|
117
148
|
requirements: []
|
118
|
-
|
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