qc-additions 0.1.0
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 +15 -0
- data/README.md +30 -0
- data/lib/qc-additions.rb +4 -0
- data/lib/qc-additions/queries.rb +22 -0
- data/lib/qc-additions/queue.rb +17 -0
- data/test/additions_test.rb +36 -0
- data/test/benchmark_test.rb +38 -0
- data/test/conn_test.rb +22 -0
- data/test/helper.rb +66 -0
- data/test/queue_test.rb +103 -0
- data/test/worker_test.rb +125 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZjQ0ZWQ3OGM2OWY2ZjVkYmVmZThkNmM4ZTg0NTE1OTMzZDBjNzQ1OQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzUxYmNmNWJmNTU0Y2U2NWQ1ZmI0ZWRhNGIwNWFiY2YxY2QyMWM4ZQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MzczZTc2MTE2ZTM0ZTlmMzAyMjc3MjMwMTkwNGUzMzcxOTU0ZTIxYWNhODNj
|
10
|
+
OTk2ZWNkNmU3ODdmYWY0NDZjYmMwNjcyYTU0N2U3YmEzNmJmMWY4NTE0MWUy
|
11
|
+
NWZjODMyOGM0NjMxZDhmOTVmMGY4ZjVkNzdiMzI2YmY3NmExYWI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDEwYTAyN2NkYWI1ZmU1ZTM5ZjRjZmRhNmNmM2E3NzUxMTRkMDA5ZDIzOThi
|
14
|
+
NmUwYzBmNjE4YWMyZmVhODM0ODRiYjJiNjIyYTkyMDIwMTg1MzExZjYzZTEx
|
15
|
+
MTc1MzI0OTYzZWJhZDQwOTBkZDgxZDk1YmY5MGU2ZTNkNjJhMjY=
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# qc-additions
|
2
|
+
|
3
|
+
|
4
|
+
This gem adds some methods to [queue_classic](https://github.com/ryandotsmith/queue_classic) queues that I found helpful:
|
5
|
+
|
6
|
+
* `enqueue_if_not_queued(method, *args)`
|
7
|
+
* `job_count(method, *args)`
|
8
|
+
* `job_exists?(method, *args)`
|
9
|
+
|
10
|
+
|
11
|
+
An index might help to speed up the `job_count` and `job_exists?` queries. Although, I haven't really tested if there is much to gain by adding this:
|
12
|
+
|
13
|
+
```SQL
|
14
|
+
CREATE INDEX idx_qc_unlocked_job_count ON queue_classic_jobs (q_name, method, args) WHERE locked_at IS NULL;
|
15
|
+
```
|
16
|
+
|
17
|
+
|
18
|
+
## Caveats when comparing args column
|
19
|
+
|
20
|
+
The method arguments are serialized to JSON. However, the comparison performed when looking for jobs in the database is a string comparison. Results might be incorrect if there is more than one way to serialize the arguments to a JSON string. It should be safe for simple things like passing a numeric id.
|
21
|
+
|
22
|
+
|
23
|
+
---
|
24
|
+
|
25
|
+
|
26
|
+
I have some of the original code from there:
|
27
|
+
|
28
|
+
* https://github.com/ryandotsmith/queue_classic/pull/92
|
29
|
+
|
30
|
+
* https://github.com/GreenplumChorus/queue_classic/commit/2719301c2813717692169c1eeab42d317df0ac59
|
data/lib/qc-additions.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module QC
|
2
|
+
module Queries
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# TODO:
|
6
|
+
# Once PostgreSQL supports JSON comparison, use it.
|
7
|
+
# But older versions should be supported too (at least >= 9.0).
|
8
|
+
|
9
|
+
def job_count(q_name, method, args)
|
10
|
+
s = "SELECT COUNT(*) FROM #{TABLE_NAME} WHERE q_name = $1 AND method = $2 AND args::text = $3 AND locked_at IS NULL"
|
11
|
+
r = Conn.execute(s, q_name, method, JSON.dump(args))
|
12
|
+
r["count"].to_i
|
13
|
+
end
|
14
|
+
|
15
|
+
def job_exists?(q_name, method, args)
|
16
|
+
s = "SELECT 1 AS one FROM #{TABLE_NAME} WHERE q_name = $1 AND method = $2 AND args::text = $3 AND locked_at IS NULL LIMIT 1"
|
17
|
+
r = Conn.execute(s, q_name, method, JSON.dump(args))
|
18
|
+
!r.nil?
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module QC
|
2
|
+
class Queue
|
3
|
+
|
4
|
+
def enqueue_if_not_queued(method, *args)
|
5
|
+
enqueue(method, *args) unless job_exists?(method, *args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def job_count(method, *args)
|
9
|
+
Queries.job_count(name, method, args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def job_exists?(method, *args)
|
13
|
+
Queries.job_exists?(name, method, args)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
class QueueTest < QCTest
|
4
|
+
|
5
|
+
def test_enqueue_if_not_queued
|
6
|
+
QC.enqueue_if_not_queued("Klass.method", "arg1", "arg2")
|
7
|
+
QC.enqueue_if_not_queued("Klass.method", "arg1", "arg2")
|
8
|
+
QC.lock
|
9
|
+
QC.enqueue_if_not_queued("Klass.method", "arg1", "arg2")
|
10
|
+
assert_equal(1, QC.job_count("Klass.method", "arg1", "arg2"))
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_job_count
|
14
|
+
#Should return the count of unstarted jobs that match both method and arguments
|
15
|
+
QC.enqueue("Klass.method", "arg1", "arg2")
|
16
|
+
QC.enqueue("Klass.method", "arg1", "arg2")
|
17
|
+
QC.enqueue("Klass.method", "arg1", "arg2")
|
18
|
+
QC.enqueue("Klass.method", "arg3", "arg4")
|
19
|
+
QC.enqueue("Klass.other_method", "arg1", "arg2")
|
20
|
+
QC.lock #start the first job
|
21
|
+
assert_equal(2, QC.job_count("Klass.method", "arg1", "arg2"))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_job_exists
|
25
|
+
# Should return true if an unstarted job with same method and arguments exists
|
26
|
+
assert_equal(false, QC.job_exists?("Klass.method"))
|
27
|
+
QC.enqueue("Klass.method")
|
28
|
+
assert_equal(true, QC.job_exists?("Klass.method"))
|
29
|
+
assert_equal(false, QC.job_exists?("Klass.method", "arg1"))
|
30
|
+
assert_equal(false, QC.job_exists?("Klass.other_method"))
|
31
|
+
assert_equal(false, QC.job_exists?("Klass.other_method", "arg1"))
|
32
|
+
QC.lock # start the job
|
33
|
+
assert_equal(false, QC.job_exists?("Klass.method"))
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
if ENV["QC_BENCHMARK"]
|
4
|
+
class BenchmarkTest < QCTest
|
5
|
+
|
6
|
+
def test_enqueue
|
7
|
+
n = 10_000
|
8
|
+
start = Time.now
|
9
|
+
n.times do
|
10
|
+
QC.enqueue("1.odd?", [])
|
11
|
+
end
|
12
|
+
assert_equal(n, QC.count)
|
13
|
+
|
14
|
+
elapsed = Time.now - start
|
15
|
+
assert_in_delta(4, elapsed, 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_dequeue
|
19
|
+
worker = QC::Worker.new
|
20
|
+
worker.running = true
|
21
|
+
n = 10_000
|
22
|
+
n.times do
|
23
|
+
QC.enqueue("1.odd?", [])
|
24
|
+
end
|
25
|
+
assert_equal(n, QC.count)
|
26
|
+
|
27
|
+
start = Time.now
|
28
|
+
n.times do
|
29
|
+
worker.work
|
30
|
+
end
|
31
|
+
elapsed = Time.now - start
|
32
|
+
|
33
|
+
assert_equal(0, QC.count)
|
34
|
+
assert_in_delta(10, elapsed, 3)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/test/conn_test.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
class ConnTest < QCTest
|
4
|
+
|
5
|
+
def test_extracts_the_segemnts_to_connect
|
6
|
+
database_url = "postgres://ryan:secret@localhost:1234/application_db"
|
7
|
+
normalized = QC::Conn.normalize_db_url(URI.parse(database_url))
|
8
|
+
assert_equal ["localhost",
|
9
|
+
1234,
|
10
|
+
nil, "",
|
11
|
+
"application_db",
|
12
|
+
"ryan",
|
13
|
+
"secret"], normalized
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_regression_database_url_without_host
|
17
|
+
database_url = "postgres:///my_db"
|
18
|
+
normalized = QC::Conn.normalize_db_url(URI.parse(database_url))
|
19
|
+
assert_equal [nil, 5432, nil, "", "my_db", nil, nil], normalized
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
$: << File.expand_path("lib")
|
2
|
+
$: << File.expand_path("test")
|
3
|
+
|
4
|
+
ENV["DATABASE_URL"] ||= "postgres:///queue_classic_test"
|
5
|
+
|
6
|
+
require "queue_classic"
|
7
|
+
require "qc-additions"
|
8
|
+
require "stringio"
|
9
|
+
require "minitest/autorun"
|
10
|
+
|
11
|
+
class QCTest < Minitest::Test
|
12
|
+
|
13
|
+
def setup
|
14
|
+
init_db
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
QC.delete_all
|
19
|
+
end
|
20
|
+
|
21
|
+
def init_db(table_name="queue_classic_jobs")
|
22
|
+
QC::Conn.execute("SET client_min_messages TO 'warning'")
|
23
|
+
QC::Setup.drop
|
24
|
+
QC::Setup.create
|
25
|
+
QC::Conn.execute(<<EOS)
|
26
|
+
DO $$
|
27
|
+
-- Set initial sequence to a large number to test the entire toolchain
|
28
|
+
-- works on integers with higher bits set.
|
29
|
+
DECLARE
|
30
|
+
quoted_name text;
|
31
|
+
quoted_size text;
|
32
|
+
BEGIN
|
33
|
+
-- Find the name of the relevant sequence.
|
34
|
+
--
|
35
|
+
-- pg_get_serial_sequence quotes identifiers as part of its
|
36
|
+
-- behavior.
|
37
|
+
SELECT name
|
38
|
+
INTO STRICT quoted_name
|
39
|
+
FROM pg_get_serial_sequence('queue_classic_jobs', 'id') AS name;
|
40
|
+
|
41
|
+
-- Don't quote, because ALTER SEQUENCE RESTART doesn't like
|
42
|
+
-- general literals, only unquoted numeric literals.
|
43
|
+
SELECT pow(2, 34)::text AS size
|
44
|
+
INTO STRICT quoted_size;
|
45
|
+
|
46
|
+
EXECUTE 'ALTER SEQUENCE ' || quoted_name ||
|
47
|
+
' RESTART ' || quoted_size || ';';
|
48
|
+
END;
|
49
|
+
$$;
|
50
|
+
EOS
|
51
|
+
end
|
52
|
+
|
53
|
+
def capture_debug_output
|
54
|
+
original_debug = ENV['DEBUG']
|
55
|
+
original_stdout = $stdout
|
56
|
+
|
57
|
+
ENV['DEBUG'] = "true"
|
58
|
+
$stdout = StringIO.new
|
59
|
+
yield
|
60
|
+
$stdout.string
|
61
|
+
ensure
|
62
|
+
ENV['DEBUG'] = original_debug
|
63
|
+
$stdout = original_stdout
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
data/test/queue_test.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
class QueueTest < QCTest
|
4
|
+
|
5
|
+
def test_enqueue
|
6
|
+
QC.enqueue("Klass.method")
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_respond_to
|
10
|
+
assert_equal(true, QC.respond_to?(:enqueue))
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_lock
|
14
|
+
QC.enqueue("Klass.method")
|
15
|
+
|
16
|
+
# See helper.rb for more information about the large initial id
|
17
|
+
# number.
|
18
|
+
expected = {:id=>(2**34).to_s, :method=>"Klass.method", :args=>[]}
|
19
|
+
assert_equal(expected, QC.lock)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_lock_when_empty
|
23
|
+
assert_nil(QC.lock)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_count
|
27
|
+
QC.enqueue("Klass.method")
|
28
|
+
assert_equal(1, QC.count)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_delete
|
32
|
+
QC.enqueue("Klass.method")
|
33
|
+
assert_equal(1, QC.count)
|
34
|
+
QC.delete(QC.lock[:id])
|
35
|
+
assert_equal(0, QC.count)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_delete_all
|
39
|
+
QC.enqueue("Klass.method")
|
40
|
+
QC.enqueue("Klass.method")
|
41
|
+
assert_equal(2, QC.count)
|
42
|
+
QC.delete_all
|
43
|
+
assert_equal(0, QC.count)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_delete_all_by_queue_name
|
47
|
+
p_queue = QC::Queue.new("priority_queue")
|
48
|
+
s_queue = QC::Queue.new("secondary_queue")
|
49
|
+
p_queue.enqueue("Klass.method")
|
50
|
+
s_queue.enqueue("Klass.method")
|
51
|
+
assert_equal(1, p_queue.count)
|
52
|
+
assert_equal(1, s_queue.count)
|
53
|
+
p_queue.delete_all
|
54
|
+
assert_equal(0, p_queue.count)
|
55
|
+
assert_equal(1, s_queue.count)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_queue_instance
|
59
|
+
queue = QC::Queue.new("queue_classic_jobs", false)
|
60
|
+
queue.enqueue("Klass.method")
|
61
|
+
assert_equal(1, queue.count)
|
62
|
+
queue.delete(queue.lock[:id])
|
63
|
+
assert_equal(0, queue.count)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_repair_after_error
|
67
|
+
queue = QC::Queue.new("queue_classic_jobs", false)
|
68
|
+
queue.enqueue("Klass.method")
|
69
|
+
assert_equal(1, queue.count)
|
70
|
+
connection = QC::Conn.connection
|
71
|
+
saved_method = connection.method(:exec)
|
72
|
+
def connection.exec(*args)
|
73
|
+
raise PGError
|
74
|
+
end
|
75
|
+
assert_raises(PG::Error) { queue.enqueue("Klass.other_method") }
|
76
|
+
assert_equal(1, queue.count)
|
77
|
+
queue.enqueue("Klass.other_method")
|
78
|
+
assert_equal(2, queue.count)
|
79
|
+
rescue PG::Error
|
80
|
+
QC::Conn.disconnect
|
81
|
+
assert false, "Expected to QC repair after connection error"
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_custom_default_queue
|
85
|
+
queue_class = Class.new do
|
86
|
+
attr_accessor :jobs
|
87
|
+
def enqueue(method, *args)
|
88
|
+
@jobs ||= []
|
89
|
+
@jobs << method
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
queue_instance = queue_class.new
|
94
|
+
QC.default_queue = queue_instance
|
95
|
+
|
96
|
+
QC.enqueue("Klass.method1")
|
97
|
+
QC.enqueue("Klass.method2")
|
98
|
+
|
99
|
+
assert_equal ["Klass.method1", "Klass.method2"], queue_instance.jobs
|
100
|
+
ensure
|
101
|
+
QC.default_queue = nil
|
102
|
+
end
|
103
|
+
end
|
data/test/worker_test.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
module TestObject
|
4
|
+
extend self
|
5
|
+
def no_args; return nil; end
|
6
|
+
def one_arg(a); return a; end
|
7
|
+
def two_args(a,b); return [a,b]; end
|
8
|
+
end
|
9
|
+
|
10
|
+
# This not only allows me to test what happens
|
11
|
+
# when a failure occurs but it also demonstrates
|
12
|
+
# how to override the worker to handle failures the way
|
13
|
+
# you want.
|
14
|
+
class TestWorker < QC::Worker
|
15
|
+
attr_accessor :failed_count
|
16
|
+
|
17
|
+
def initialize(*args)
|
18
|
+
super(*args)
|
19
|
+
@failed_count = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_failure(job,e)
|
23
|
+
@failed_count += 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class WorkerTest < QCTest
|
28
|
+
|
29
|
+
def test_work
|
30
|
+
QC.enqueue("TestObject.no_args")
|
31
|
+
worker = TestWorker.new
|
32
|
+
assert_equal(1, QC.count)
|
33
|
+
worker.work
|
34
|
+
assert_equal(0, QC.count)
|
35
|
+
assert_equal(0, worker.failed_count)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_failed_job
|
39
|
+
QC.enqueue("TestObject.not_a_method")
|
40
|
+
worker = TestWorker.new
|
41
|
+
worker.work
|
42
|
+
assert_equal(1, worker.failed_count)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_failed_job_is_logged
|
46
|
+
output = capture_debug_output do
|
47
|
+
QC.enqueue("TestObject.not_a_method")
|
48
|
+
QC::Worker.new.work
|
49
|
+
end
|
50
|
+
expected_output = /lib=queue-classic at=handle_failure job={:id=>"\d+", :method=>"TestObject.not_a_method", :args=>\[\]} error=#<NoMethodError: undefined method `not_a_method' for TestObject:Module>/
|
51
|
+
assert_match(expected_output, output, "=== debug output ===\n #{output}")
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_log_yield
|
55
|
+
output = capture_debug_output do
|
56
|
+
QC.log_yield(:action => "test") do
|
57
|
+
0 == 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
expected_output = /lib=queue-classic action=test elapsed=\d*/
|
61
|
+
assert_match(expected_output, output, "=== debug output ===\n #{output}")
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_log
|
65
|
+
output = capture_debug_output do
|
66
|
+
QC.log(:action => "test")
|
67
|
+
end
|
68
|
+
expected_output = /lib=queue-classic action=test/
|
69
|
+
assert_match(expected_output, output, "=== debug output ===\n #{output}")
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_work_with_no_args
|
73
|
+
QC.enqueue("TestObject.no_args")
|
74
|
+
worker = TestWorker.new
|
75
|
+
r = worker.work
|
76
|
+
assert_nil(r)
|
77
|
+
assert_equal(0, worker.failed_count)
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_work_with_one_arg
|
81
|
+
QC.enqueue("TestObject.one_arg", "1")
|
82
|
+
worker = TestWorker.new
|
83
|
+
r = worker.work
|
84
|
+
assert_equal("1", r)
|
85
|
+
assert_equal(0, worker.failed_count)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_work_with_two_args
|
89
|
+
QC.enqueue("TestObject.two_args", "1", 2)
|
90
|
+
worker = TestWorker.new
|
91
|
+
r = worker.work
|
92
|
+
assert_equal(["1", 2], r)
|
93
|
+
assert_equal(0, worker.failed_count)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_work_custom_queue
|
97
|
+
p_queue = QC::Queue.new("priority_queue")
|
98
|
+
p_queue.enqueue("TestObject.two_args", "1", 2)
|
99
|
+
worker = TestWorker.new(q_name: "priority_queue")
|
100
|
+
r = worker.work
|
101
|
+
assert_equal(["1", 2], r)
|
102
|
+
assert_equal(0, worker.failed_count)
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_worker_listens_on_chan
|
106
|
+
p_queue = QC::Queue.new("priority_queue")
|
107
|
+
p_queue.enqueue("TestObject.two_args", "1", 2)
|
108
|
+
worker = TestWorker.new(q_name: "priority_queue", listening_worker: true)
|
109
|
+
r = worker.work
|
110
|
+
assert_equal(["1", 2], r)
|
111
|
+
assert_equal(0, worker.failed_count)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_worker_ueses_one_conn
|
115
|
+
QC.enqueue("TestObject.no_args")
|
116
|
+
worker = TestWorker.new
|
117
|
+
worker.work
|
118
|
+
assert_equal(
|
119
|
+
1,
|
120
|
+
QC::Conn.execute("SELECT count(*) from pg_stat_activity where datname = current_database()")["count"].to_i,
|
121
|
+
"Multiple connections found -- are there open connections to #{ QC::Conn.db_url } in other terminals?"
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: qc-additions
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jakob Rath
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: queue_classic
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.0
|
27
|
+
description: Add some methods to queue_classic to determine whether a job exists or
|
28
|
+
how many times a given job is already queued.
|
29
|
+
email: mail@jakobrath.eu
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- README.md
|
35
|
+
- lib/qc-additions/queries.rb
|
36
|
+
- lib/qc-additions/queue.rb
|
37
|
+
- lib/qc-additions.rb
|
38
|
+
- test/additions_test.rb
|
39
|
+
- test/benchmark_test.rb
|
40
|
+
- test/conn_test.rb
|
41
|
+
- test/helper.rb
|
42
|
+
- test/queue_test.rb
|
43
|
+
- test/worker_test.rb
|
44
|
+
homepage: https://github.com/JakobR/qc-additions
|
45
|
+
licenses: []
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.0.3
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: Add some methods to queue_classic.
|
67
|
+
test_files:
|
68
|
+
- test/additions_test.rb
|
69
|
+
- test/benchmark_test.rb
|
70
|
+
- test/conn_test.rb
|
71
|
+
- test/queue_test.rb
|
72
|
+
- test/worker_test.rb
|
73
|
+
has_rdoc:
|