queue_classic 2.1.4 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/queue_classic.rb +8 -8
- data/lib/queue_classic/conn.rb +46 -29
- data/lib/queue_classic/queries.rb +2 -2
- data/lib/queue_classic/tasks.rb +1 -1
- data/lib/queue_classic/worker.rb +4 -7
- data/readme.md +31 -12
- data/sql/create_table.sql +13 -3
- data/test/benchmark_test.rb +38 -0
- data/test/conn_test.rb +22 -0
- data/test/helper.rb +16 -4
- data/test/queue_test.rb +21 -1
- data/test/worker_test.rb +27 -0
- metadata +5 -17
data/lib/queue_classic.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "pg"
|
2
2
|
require "uri"
|
3
|
-
require "
|
3
|
+
require "json"
|
4
4
|
|
5
5
|
require "queue_classic/conn"
|
6
6
|
require "queue_classic/queries"
|
@@ -16,11 +16,8 @@ module QC
|
|
16
16
|
|
17
17
|
# You can use the APP_NAME to query for
|
18
18
|
# postgres related process information in the
|
19
|
-
# pg_stat_activity table.
|
20
|
-
|
21
|
-
if APP_NAME = ENV["QC_APP_NAME"]
|
22
|
-
Conn.execute("SET application_name = '#{APP_NAME}'")
|
23
|
-
end
|
19
|
+
# pg_stat_activity table.
|
20
|
+
APP_NAME = ENV["QC_APP_NAME"] || "queue_classic"
|
24
21
|
|
25
22
|
# Why do you want to change the table name?
|
26
23
|
# Just deal with the default OK?
|
@@ -66,6 +63,10 @@ module QC
|
|
66
63
|
default_queue.respond_to?(method_name)
|
67
64
|
end
|
68
65
|
|
66
|
+
def self.default_queue=(queue)
|
67
|
+
@default_queue = queue
|
68
|
+
end
|
69
|
+
|
69
70
|
def self.default_queue
|
70
71
|
@default_queue ||= begin
|
71
72
|
Queue.new(QUEUE)
|
@@ -91,7 +92,7 @@ module QC
|
|
91
92
|
if block_given?
|
92
93
|
start = Time.now
|
93
94
|
result = yield
|
94
|
-
data.merge(:elapsed => Time.now -
|
95
|
+
data.merge(:elapsed => Integer((Time.now - t0)*1000))
|
95
96
|
end
|
96
97
|
data.reduce(out=String.new) do |s, tup|
|
97
98
|
s << [tup.first, tup.last].join("=") << " "
|
@@ -99,5 +100,4 @@ module QC
|
|
99
100
|
puts(out) if ENV["DEBUG"]
|
100
101
|
return result
|
101
102
|
end
|
102
|
-
|
103
103
|
end
|
data/lib/queue_classic/conn.rb
CHANGED
@@ -27,26 +27,11 @@ module QC
|
|
27
27
|
execute('NOTIFY "' + chan + '"') #quotes matter
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
def unlisten(chan)
|
36
|
-
log(:at => "UNLISTEN")
|
37
|
-
execute('UNLISTEN "' + chan + '"') #quotes matter
|
38
|
-
end
|
39
|
-
|
40
|
-
def drain_notify
|
41
|
-
until connection.notifies.nil?
|
42
|
-
log(:at => "drain_notifications")
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def wait_for_notify(t)
|
47
|
-
connection.wait_for_notify(t) do |event, pid, msg|
|
48
|
-
log(:at => "received_notification")
|
49
|
-
end
|
30
|
+
def wait(chan, t)
|
31
|
+
listen(chan)
|
32
|
+
wait_for_notify(t)
|
33
|
+
unlisten(chan)
|
34
|
+
drain_notify
|
50
35
|
end
|
51
36
|
|
52
37
|
def transaction
|
@@ -69,7 +54,7 @@ module QC
|
|
69
54
|
end
|
70
55
|
|
71
56
|
def connection=(connection)
|
72
|
-
unless connection.
|
57
|
+
unless connection.is_a? PG::Connection
|
73
58
|
c = connection.class
|
74
59
|
err = "connection must be an instance of PG::Connection, but was #{c}"
|
75
60
|
raise(ArgumentError, err)
|
@@ -85,20 +70,28 @@ module QC
|
|
85
70
|
|
86
71
|
def connect
|
87
72
|
log(:at => "establish_conn")
|
88
|
-
conn = PGconn.connect(
|
89
|
-
db_url.host.gsub(/%2F/i, '/'), # host or percent-encoded socket path
|
90
|
-
db_url.port || 5432,
|
91
|
-
nil, '', #opts, tty
|
92
|
-
db_url.path.gsub("/",""), # database name
|
93
|
-
db_url.user,
|
94
|
-
db_url.password
|
95
|
-
)
|
73
|
+
conn = PGconn.connect(*normalize_db_url(db_url))
|
96
74
|
if conn.status != PGconn::CONNECTION_OK
|
97
75
|
log(:error => conn.error)
|
98
76
|
end
|
77
|
+
conn.exec("SET application_name = '#{QC::APP_NAME}'")
|
99
78
|
conn
|
100
79
|
end
|
101
80
|
|
81
|
+
def normalize_db_url(url)
|
82
|
+
host = url.host
|
83
|
+
host = host.gsub(/%2F/i, '/') if host
|
84
|
+
|
85
|
+
[
|
86
|
+
host, # host or percent-encoded socket path
|
87
|
+
url.port || 5432,
|
88
|
+
nil, '', #opts, tty
|
89
|
+
url.path.gsub("/",""), # database name
|
90
|
+
url.user,
|
91
|
+
url.password
|
92
|
+
]
|
93
|
+
end
|
94
|
+
|
102
95
|
def db_url
|
103
96
|
return @db_url if @db_url
|
104
97
|
url = ENV["QC_DATABASE_URL"] ||
|
@@ -107,9 +100,33 @@ module QC
|
|
107
100
|
@db_url = URI.parse(url)
|
108
101
|
end
|
109
102
|
|
103
|
+
private
|
104
|
+
|
110
105
|
def log(msg)
|
111
106
|
QC.log(msg)
|
112
107
|
end
|
113
108
|
|
109
|
+
def listen(chan)
|
110
|
+
log(:at => "LISTEN")
|
111
|
+
execute('LISTEN "' + chan + '"') #quotes matter
|
112
|
+
end
|
113
|
+
|
114
|
+
def unlisten(chan)
|
115
|
+
log(:at => "UNLISTEN")
|
116
|
+
execute('UNLISTEN "' + chan + '"') #quotes matter
|
117
|
+
end
|
118
|
+
|
119
|
+
def wait_for_notify(t)
|
120
|
+
connection.wait_for_notify(t) do |event, pid, msg|
|
121
|
+
log(:at => "received_notification")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def drain_notify
|
126
|
+
until connection.notifies.nil?
|
127
|
+
log(:at => "drain_notifications")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
114
131
|
end
|
115
132
|
end
|
@@ -5,7 +5,7 @@ module QC
|
|
5
5
|
def insert(q_name, method, args, chan=nil)
|
6
6
|
QC.log_yield(:action => "insert_job") do
|
7
7
|
s = "INSERT INTO #{TABLE_NAME} (q_name, method, args) VALUES ($1, $2, $3)"
|
8
|
-
res = Conn.execute(s, q_name, method,
|
8
|
+
res = Conn.execute(s, q_name, method, JSON.dump(args))
|
9
9
|
Conn.notify(chan) if chan
|
10
10
|
end
|
11
11
|
end
|
@@ -16,7 +16,7 @@ module QC
|
|
16
16
|
{
|
17
17
|
:id => r["id"],
|
18
18
|
:method => r["method"],
|
19
|
-
:args =>
|
19
|
+
:args => JSON.parse(r["args"])
|
20
20
|
}
|
21
21
|
end
|
22
22
|
end
|
data/lib/queue_classic/tasks.rb
CHANGED
data/lib/queue_classic/worker.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module QC
|
2
2
|
class Worker
|
3
3
|
|
4
|
-
|
4
|
+
attr_accessor :queue, :running
|
5
5
|
# In the case no arguments are passed to the initializer,
|
6
6
|
# the defaults are pulled from the environment variables.
|
7
7
|
def initialize(args={})
|
@@ -113,21 +113,18 @@ module QC
|
|
113
113
|
def wait(t)
|
114
114
|
if @listening_worker
|
115
115
|
log(:at => "listen_wait", :wait => t)
|
116
|
-
Conn.
|
117
|
-
Conn.wait_for_notify(t)
|
118
|
-
Conn.unlisten(@queue.chan)
|
119
|
-
Conn.drain_notify
|
120
|
-
log(:at => "finished_listening")
|
116
|
+
Conn.wait(@queue.chan)
|
121
117
|
else
|
122
118
|
log(:at => "sleep_wait", :wait => t)
|
123
119
|
Kernel.sleep(t)
|
124
120
|
end
|
121
|
+
log(:at => "finished_listening")
|
125
122
|
end
|
126
123
|
|
127
124
|
# This method will be called when an exception
|
128
125
|
# is raised during the execution of the job.
|
129
126
|
def handle_failure(job,e)
|
130
|
-
log(:at => "handle_failure")
|
127
|
+
log(:at => "handle_failure", :job => job, :error => e.inspect)
|
131
128
|
end
|
132
129
|
|
133
130
|
# This method should be overriden if
|
data/readme.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# queue_classic
|
2
2
|
|
3
|
-
v2.
|
3
|
+
v2.2.0
|
4
4
|
|
5
5
|
queue_classic provides a simple interface to a PostgreSQL-backed message queue. queue_classic specializes in concurrent locking and minimizing database load while providing a simple, intuitive developer experience. queue_classic assumes that you are already using PostgreSQL in your production environment and that adding another dependency (e.g. redis, beanstalkd, 0mq) is undesirable.
|
6
6
|
|
@@ -14,10 +14,11 @@ Features:
|
|
14
14
|
|
15
15
|
Contents:
|
16
16
|
|
17
|
-
* [Documentation](http://rubydoc.info/gems/queue_classic/2.
|
17
|
+
* [Documentation](http://rubydoc.info/gems/queue_classic/2.2.0/frames)
|
18
18
|
* [Usage](#usage)
|
19
19
|
* [Setup](#setup)
|
20
20
|
* [Configuration](#configuration)
|
21
|
+
* [Support](#support)
|
21
22
|
* [Hacking](#hacking-on-queue_classic)
|
22
23
|
* [License](#license)
|
23
24
|
|
@@ -30,6 +31,8 @@ There are 2 ways to use queue_classic.
|
|
30
31
|
|
31
32
|
### Producing Jobs
|
32
33
|
|
34
|
+
The first argument is a string which represents a ruby object and a method name. The second argument(s) will be passed along as arguments to the method invocation defined by the first argument. The set of arguments will be encoded as JSON in the database.
|
35
|
+
|
33
36
|
```ruby
|
34
37
|
# This method has no arguments.
|
35
38
|
QC.enqueue("Time.now")
|
@@ -51,12 +54,6 @@ p_queue = QC::Queue.new("priority_queue")
|
|
51
54
|
p_queue.enqueue("Kernel.puts", ["hello", "world"])
|
52
55
|
```
|
53
56
|
|
54
|
-
QueueClassic uses [MultiJSON](https://github.com/intridea/multi_json) to encode the job's payload.
|
55
|
-
|
56
|
-
```ruby
|
57
|
-
MultiJson.dump({"test" => "test"})
|
58
|
-
```
|
59
|
-
|
60
57
|
### Working Jobs
|
61
58
|
|
62
59
|
There are two ways to work jobs. The first approach is to use the Rake task. The second approach is to use a custom executable.
|
@@ -90,9 +87,6 @@ This example is probably not production ready; however, it serves as an example
|
|
90
87
|
require 'timeout'
|
91
88
|
require 'queue_classic'
|
92
89
|
|
93
|
-
trap('INT') {exit}
|
94
|
-
trap('TERM') {worker.stop}
|
95
|
-
|
96
90
|
FailedQueue = QC::Queue.new("failed_jobs")
|
97
91
|
|
98
92
|
class MyWorker < QC::Worker
|
@@ -103,6 +97,9 @@ end
|
|
103
97
|
|
104
98
|
worker = MyWorker.new(max_attempts: 10, listening_worker: true)
|
105
99
|
|
100
|
+
trap('INT') {exit}
|
101
|
+
trap('TERM') {worker.stop}
|
102
|
+
|
106
103
|
loop do
|
107
104
|
job = worker.lock_job
|
108
105
|
Thread.new do
|
@@ -132,7 +129,7 @@ Declare dependencies in Gemfile.
|
|
132
129
|
|
133
130
|
```ruby
|
134
131
|
source "http://rubygems.org"
|
135
|
-
gem "queue_classic", "2.
|
132
|
+
gem "queue_classic", "2.2.0"
|
136
133
|
```
|
137
134
|
|
138
135
|
Require these files in your Rakefile so that you can run `rake qc:work`.
|
@@ -181,6 +178,13 @@ $ bundle exec rake qc:drop
|
|
181
178
|
|
182
179
|
All configuration takes place in the form of environment vars. See [queue_classic.rb](https://github.com/ryandotsmith/queue_classic/blob/master/lib/queue_classic.rb#L23-62) for a list of options.
|
183
180
|
|
181
|
+
## JSON
|
182
|
+
|
183
|
+
If you are running PostgreSQL 9.2 or higher, queue_classic will use the [json](http://www.postgresql.org/docs/9.2/static/datatype-json.html) datatype for storing arguments. Versions 9.1 and lower will use the 'text' column. If you have installed queue_classic prior to version 2.1.4 and are running PostgreSQL >= 9.2, run the following to switch to using the json type:
|
184
|
+
```
|
185
|
+
alter table queue_classic_jobs alter column args type json using (args::json);
|
186
|
+
```
|
187
|
+
|
184
188
|
## Logging
|
185
189
|
|
186
190
|
By default queue_classic does not talk very much.
|
@@ -191,8 +195,23 @@ you can enable the debug output by setting the `DEBUG` environment variable:
|
|
191
195
|
export DEBUG="true"
|
192
196
|
```
|
193
197
|
|
198
|
+
## Support
|
199
|
+
|
200
|
+
If you think you have found a bug, feel free to open an issue. Use the following template for the new issue:
|
201
|
+
|
202
|
+
1. List Versions: Ruby, PostgreSQL, queue_classic.
|
203
|
+
2. Define what you would have expcted to happen.
|
204
|
+
3. List what actually happened.
|
205
|
+
4. Provide sample codes & commands which will reproduce the problem.
|
206
|
+
|
207
|
+
If you have general questions about how to use queue_classic, send a message to the mailing list:
|
208
|
+
|
209
|
+
https://groups.google.com/d/forum/queue_classic
|
210
|
+
|
194
211
|
## Hacking on queue_classic
|
195
212
|
|
213
|
+
[![Build Status](https://drone.io/github.com/ryandotsmith/queue_classic/status.png)](https://drone.io/github.com/ryandotsmith/queue_classic/latest)
|
214
|
+
|
196
215
|
### Dependencies
|
197
216
|
|
198
217
|
* Ruby 1.9.2 (tests work in 1.8.7 but compatibility is not guaranteed or supported)
|
data/sql/create_table.sql
CHANGED
@@ -1,9 +1,19 @@
|
|
1
|
+
do $$ begin
|
2
|
+
|
1
3
|
CREATE TABLE queue_classic_jobs (
|
2
4
|
id bigserial PRIMARY KEY,
|
3
|
-
q_name
|
4
|
-
method
|
5
|
-
args
|
5
|
+
q_name text not null check (length(q_name) > 0),
|
6
|
+
method text not null check (length(method) > 0),
|
7
|
+
args text not null,
|
6
8
|
locked_at timestamptz
|
7
9
|
);
|
8
10
|
|
11
|
+
-- If json type is available, use it for the args column.
|
12
|
+
perform * from pg_type where typname = 'json';
|
13
|
+
if found then
|
14
|
+
alter table queue_classic_jobs alter column args type json using (args::json);
|
15
|
+
end if;
|
16
|
+
|
17
|
+
end $$ language plpgsql;
|
18
|
+
|
9
19
|
CREATE INDEX idx_qc_on_name_only_unlocked ON queue_classic_jobs (q_name, id) WHERE locked_at IS NULL;
|
@@ -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
CHANGED
@@ -4,10 +4,10 @@ $: << File.expand_path("test")
|
|
4
4
|
ENV["DATABASE_URL"] ||= "postgres:///queue_classic_test"
|
5
5
|
|
6
6
|
require "queue_classic"
|
7
|
-
require "
|
8
|
-
|
7
|
+
require "stringio"
|
8
|
+
require "minitest/autorun"
|
9
9
|
|
10
|
-
class QCTest <
|
10
|
+
class QCTest < Minitest::Test
|
11
11
|
|
12
12
|
def setup
|
13
13
|
init_db
|
@@ -47,7 +47,19 @@ BEGIN
|
|
47
47
|
END;
|
48
48
|
$$;
|
49
49
|
EOS
|
50
|
-
|
50
|
+
end
|
51
|
+
|
52
|
+
def capture_debug_output
|
53
|
+
original_debug = ENV['DEBUG']
|
54
|
+
original_stdout = $stdout
|
55
|
+
|
56
|
+
ENV['DEBUG'] = "true"
|
57
|
+
$stdout = StringIO.new
|
58
|
+
yield
|
59
|
+
$stdout.string
|
60
|
+
ensure
|
61
|
+
ENV['DEBUG'] = original_debug
|
62
|
+
$stdout = original_stdout
|
51
63
|
end
|
52
64
|
|
53
65
|
end
|
data/test/queue_test.rb
CHANGED
@@ -72,7 +72,7 @@ class QueueTest < QCTest
|
|
72
72
|
def connection.exec(*args)
|
73
73
|
raise PGError
|
74
74
|
end
|
75
|
-
assert_raises(PG::Error) { queue.enqueue("Klass.other_method") }
|
75
|
+
assert_raises(PG::Error) { queue.enqueue("Klass.other_method") }
|
76
76
|
assert_equal(1, queue.count)
|
77
77
|
queue.enqueue("Klass.other_method")
|
78
78
|
assert_equal(2, queue.count)
|
@@ -80,4 +80,24 @@ class QueueTest < QCTest
|
|
80
80
|
QC::Conn.disconnect
|
81
81
|
assert false, "Expected to QC repair after connection error"
|
82
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
|
83
103
|
end
|
data/test/worker_test.rb
CHANGED
@@ -42,6 +42,33 @@ class WorkerTest < QCTest
|
|
42
42
|
assert_equal(1, worker.failed_count)
|
43
43
|
end
|
44
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
|
+
|
45
72
|
def test_work_with_no_args
|
46
73
|
QC.enqueue("TestObject.no_args")
|
47
74
|
worker = TestWorker.new
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queue_classic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,22 +27,6 @@ dependencies:
|
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 0.15.1
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: multi_json
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ~>
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 1.7.2
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 1.7.2
|
46
30
|
description: queue_classic is a queueing library for Ruby apps. (Rails, Sinatra, Etc...)
|
47
31
|
queue_classic features asynchronous job polling, database maintained locks and no
|
48
32
|
ridiculous dependencies. As a matter of fact, queue_classic only requires pg.
|
@@ -62,6 +46,8 @@ files:
|
|
62
46
|
- lib/queue_classic/tasks.rb
|
63
47
|
- lib/queue_classic/worker.rb
|
64
48
|
- lib/queue_classic.rb
|
49
|
+
- test/benchmark_test.rb
|
50
|
+
- test/conn_test.rb
|
65
51
|
- test/helper.rb
|
66
52
|
- test/queue_test.rb
|
67
53
|
- test/worker_test.rb
|
@@ -91,5 +77,7 @@ signing_key:
|
|
91
77
|
specification_version: 3
|
92
78
|
summary: postgres backed queue
|
93
79
|
test_files:
|
80
|
+
- test/benchmark_test.rb
|
81
|
+
- test/conn_test.rb
|
94
82
|
- test/queue_test.rb
|
95
83
|
- test/worker_test.rb
|