queue_classic 1.0.2 → 2.0.0rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/queue_classic.rb +67 -8
- data/lib/queue_classic/conn.rb +97 -0
- data/lib/queue_classic/okjson.rb +15 -40
- data/lib/queue_classic/queries.rb +56 -0
- data/lib/queue_classic/queue.rb +14 -49
- data/lib/queue_classic/tasks.rb +25 -14
- data/lib/queue_classic/worker.rb +37 -23
- data/readme.md +520 -31
- data/test/helper.rb +21 -17
- data/test/queue_test.rb +29 -60
- data/test/worker_test.rb +57 -25
- metadata +10 -19
- data/lib/queue_classic/database.rb +0 -188
- data/lib/queue_classic/durable_array.rb +0 -51
- data/lib/queue_classic/job.rb +0 -42
- data/lib/queue_classic/logger.rb +0 -17
- data/test/database_helpers.rb +0 -13
- data/test/database_test.rb +0 -73
- data/test/durable_array_test.rb +0 -94
- data/test/job_test.rb +0 -82
@@ -1,51 +0,0 @@
|
|
1
|
-
module QC
|
2
|
-
class DurableArray
|
3
|
-
|
4
|
-
def initialize(database)
|
5
|
-
@database = database
|
6
|
-
@table_name = @database.table_name
|
7
|
-
@top_boundary = @database.top_boundary
|
8
|
-
end
|
9
|
-
|
10
|
-
def <<(details)
|
11
|
-
execute("INSERT INTO #{@table_name} (details) VALUES ($1)", OkJson.encode(details))
|
12
|
-
@database.notify if ENV["QC_LISTENING_WORKER"] == "true"
|
13
|
-
end
|
14
|
-
|
15
|
-
def count
|
16
|
-
execute("SELECT COUNT(*) FROM #{@table_name}")[0]["count"].to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
def delete(job)
|
20
|
-
execute("DELETE FROM #{@table_name} WHERE id = $1;", job.id)
|
21
|
-
job
|
22
|
-
end
|
23
|
-
|
24
|
-
def search_details_column(q)
|
25
|
-
find_many { ["SELECT * FROM #{@table_name} WHERE details LIKE $1;", "%#{q}%"] }
|
26
|
-
end
|
27
|
-
|
28
|
-
def first
|
29
|
-
find_one { ["SELECT * FROM lock_head($1, $2);", @table_name, @top_boundary] }
|
30
|
-
end
|
31
|
-
|
32
|
-
def each
|
33
|
-
execute("SELECT * FROM #{@table_name} ORDER BY id ASC;").each do |r|
|
34
|
-
yield Job.new(r)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def find_one(&blk)
|
39
|
-
find_many(&blk).pop
|
40
|
-
end
|
41
|
-
|
42
|
-
def find_many
|
43
|
-
execute(*yield).map { |r| Job.new(r) }
|
44
|
-
end
|
45
|
-
|
46
|
-
def execute(sql, *params)
|
47
|
-
@database.execute(sql, *params)
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
data/lib/queue_classic/job.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
module QC
|
2
|
-
class Job
|
3
|
-
attr_accessor :id, :details, :locked_at
|
4
|
-
|
5
|
-
def initialize(args={})
|
6
|
-
@id = args["id"]
|
7
|
-
@details = OkJson.decode(args["details"])
|
8
|
-
@locked_at = args["locked_at"]
|
9
|
-
end
|
10
|
-
|
11
|
-
def klass
|
12
|
-
eval(details["job"].split(".").first)
|
13
|
-
end
|
14
|
-
|
15
|
-
def method
|
16
|
-
details["job"].split(".").last
|
17
|
-
end
|
18
|
-
|
19
|
-
def signature
|
20
|
-
details["job"]
|
21
|
-
end
|
22
|
-
|
23
|
-
def params
|
24
|
-
return [] unless details["params"]
|
25
|
-
params = details["params"]
|
26
|
-
if params.length == 1
|
27
|
-
return params[0]
|
28
|
-
else
|
29
|
-
params
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def work
|
34
|
-
if params.class == Array
|
35
|
-
klass.send(method,*params)
|
36
|
-
else
|
37
|
-
klass.send(method,params)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
end
|
data/lib/queue_classic/logger.rb
DELETED
data/test/database_helpers.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
module DatabaseHelpers
|
2
|
-
|
3
|
-
def init_db(table_name="queue_classic_jobs")
|
4
|
-
database = QC::Database.new(table_name)
|
5
|
-
database.execute("SET client_min_messages TO 'warning'")
|
6
|
-
database.execute("DROP TABLE IF EXISTS #{table_name} CASCADE")
|
7
|
-
database.execute("CREATE TABLE #{table_name} (id serial, details text, locked_at timestamp)")
|
8
|
-
database.load_functions
|
9
|
-
database.disconnect
|
10
|
-
database
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
data/test/database_test.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
require File.expand_path("../helper.rb", __FILE__)
|
2
|
-
|
3
|
-
context "DatabaseTest" do
|
4
|
-
|
5
|
-
setup do
|
6
|
-
@database = init_db
|
7
|
-
end
|
8
|
-
|
9
|
-
teardown do
|
10
|
-
@database.disconnect
|
11
|
-
end
|
12
|
-
|
13
|
-
test "drain_notify clears all of the notifications" do
|
14
|
-
@database.listen
|
15
|
-
@database.execute("NOTIFY queue_classic_jobs, 'hello'")
|
16
|
-
|
17
|
-
assert ! @database.connection.notifies.nil?
|
18
|
-
assert @database.connection.notifies.nil?
|
19
|
-
|
20
|
-
@database.execute("NOTIFY queue_classic_jobs, 'hello'")
|
21
|
-
@database.execute("NOTIFY queue_classic_jobs, 'hello'")
|
22
|
-
@database.execute("NOTIFY queue_classic_jobs, 'hello'")
|
23
|
-
|
24
|
-
@database.drain_notify
|
25
|
-
assert @database.connection.notifies.nil?
|
26
|
-
end
|
27
|
-
|
28
|
-
test "execute should return rows" do
|
29
|
-
result = @database.execute 'SELECT 11 foo, 22 bar;'
|
30
|
-
assert_equal [{'foo'=>'11', 'bar'=>'22'}], result.to_a
|
31
|
-
end
|
32
|
-
|
33
|
-
test "should raise error on failure" do
|
34
|
-
assert_raises PGError do
|
35
|
-
@database.execute 'SELECT unknown FROM missing;'
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
test "execute should accept parameters" do
|
40
|
-
result = @database.execute 'SELECT $2::int b, $1::int a, $1::int + $2::int c;', 123, '456'
|
41
|
-
assert_equal [{"a"=>"123", "b"=>"456", "c"=>"579"}], result.to_a
|
42
|
-
end
|
43
|
-
|
44
|
-
def job_count
|
45
|
-
@database.execute('SELECT COUNT(*) FROM queue_classic_jobs')[0].values.first.to_i
|
46
|
-
end
|
47
|
-
|
48
|
-
test "transaction should commit" do
|
49
|
-
assert_equal true, @database.transaction_idle?
|
50
|
-
assert_equal 0, job_count
|
51
|
-
@database.transaction do
|
52
|
-
assert_equal false, @database.transaction_idle?
|
53
|
-
assert_equal 0, job_count
|
54
|
-
@database.execute "INSERT INTO queue_classic_jobs (details) VALUES ('test');"
|
55
|
-
assert_equal false, @database.transaction_idle?
|
56
|
-
assert_equal 1, job_count
|
57
|
-
end
|
58
|
-
assert_equal true, @database.transaction_idle?
|
59
|
-
assert_equal 1, job_count
|
60
|
-
end
|
61
|
-
|
62
|
-
test "transaction should rollback if there's an error" do
|
63
|
-
assert_raises RuntimeError do
|
64
|
-
@database.transaction do
|
65
|
-
@database.execute "INSERT INTO queue_classic_jobs (details) VALUES ('test');"
|
66
|
-
assert_equal 1, job_count
|
67
|
-
raise "force rollback"
|
68
|
-
end
|
69
|
-
end
|
70
|
-
assert_equal 0, job_count
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
data/test/durable_array_test.rb
DELETED
@@ -1,94 +0,0 @@
|
|
1
|
-
require File.expand_path("../helper.rb", __FILE__)
|
2
|
-
|
3
|
-
context "DurableArray" do
|
4
|
-
|
5
|
-
setup do
|
6
|
-
@database = init_db
|
7
|
-
@array = QC::DurableArray.new(@database)
|
8
|
-
end
|
9
|
-
|
10
|
-
teardown do
|
11
|
-
@database.disconnect
|
12
|
-
end
|
13
|
-
|
14
|
-
test "decode json into hash" do
|
15
|
-
@array << {"test" => "ok"}
|
16
|
-
assert_equal({"test" => "ok"}, @array.first.details)
|
17
|
-
end
|
18
|
-
|
19
|
-
test "count returns number of rows" do
|
20
|
-
@array << {"test" => "ok"}
|
21
|
-
assert_equal 1, @array.count
|
22
|
-
@array << {"test" => "ok"}
|
23
|
-
assert_equal 2, @array.count
|
24
|
-
end
|
25
|
-
|
26
|
-
test "first returns first job" do
|
27
|
-
job = {"job" => "one"}
|
28
|
-
@array << job
|
29
|
-
assert_equal job, @array.first.details
|
30
|
-
end
|
31
|
-
|
32
|
-
test "passes through strings with quotes" do
|
33
|
-
job = {"foo'bar\"baz" => 'abc\\def'}
|
34
|
-
@array << job
|
35
|
-
assert_equal job, @array.first.details
|
36
|
-
end
|
37
|
-
|
38
|
-
test "passes through newlines" do
|
39
|
-
job = {"word" => "line1\nline2\nline3\n"}
|
40
|
-
@array << job
|
41
|
-
assert_equal job, @array.first.details
|
42
|
-
end
|
43
|
-
|
44
|
-
test "first returns first job when many are in the array" do
|
45
|
-
@array << {"job" => "one"}
|
46
|
-
@array << {"job" => "two"}
|
47
|
-
assert_equal({"job" => "one"}, @array.first.details)
|
48
|
-
end
|
49
|
-
|
50
|
-
test "find_many returns empty array when nothing is found" do
|
51
|
-
assert_equal([], @array.find_many {"select * from queue_classic_jobs"})
|
52
|
-
end
|
53
|
-
|
54
|
-
test "delete removes job from the array" do
|
55
|
-
@array << {"job" => "one"}
|
56
|
-
job = @array.first
|
57
|
-
|
58
|
-
assert_equal( {"job" => "one"}, job.details)
|
59
|
-
|
60
|
-
assert_equal(1,@array.count)
|
61
|
-
@array.delete(job)
|
62
|
-
assert_equal(0,@array.count)
|
63
|
-
end
|
64
|
-
|
65
|
-
test "delete returns job after delete" do
|
66
|
-
@array << {"job" => "one"}
|
67
|
-
job = @array.first
|
68
|
-
|
69
|
-
assert_equal({"job" => "one"}, job.details)
|
70
|
-
|
71
|
-
res = @array.delete(job)
|
72
|
-
assert_equal({"job" => "one"}, res.details)
|
73
|
-
end
|
74
|
-
|
75
|
-
test "each yields the details for each job" do
|
76
|
-
@array << {"job" => "one"}
|
77
|
-
@array << {"job" => "two"}
|
78
|
-
results = []
|
79
|
-
@array.each {|v| results << v.details}
|
80
|
-
assert_equal([{"job" => "one"},{"job" => "two"}], results)
|
81
|
-
end
|
82
|
-
|
83
|
-
test "search" do
|
84
|
-
@array << {"job" => "A.signature"}
|
85
|
-
jobs = @array.search_details_column("A.signature")
|
86
|
-
assert_equal "A.signature", jobs.first.signature
|
87
|
-
end
|
88
|
-
|
89
|
-
test "search when data will not match" do
|
90
|
-
@array << {"job" => "A.signature"}
|
91
|
-
jobs = @array.search_details_column("B.signature")
|
92
|
-
assert_equal [], jobs
|
93
|
-
end
|
94
|
-
end
|
data/test/job_test.rb
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
require File.expand_path("../helper.rb", __FILE__)
|
2
|
-
|
3
|
-
context "Job" do
|
4
|
-
|
5
|
-
test "initialize takes details as JSON" do
|
6
|
-
job = QC::Job.new(
|
7
|
-
"id" => 1,
|
8
|
-
"details" => "{\"arg\":1}",
|
9
|
-
"locked_at" => nil
|
10
|
-
)
|
11
|
-
assert_equal({"arg" => 1}, job.details)
|
12
|
-
end
|
13
|
-
|
14
|
-
test "signature returns the class and method" do
|
15
|
-
job = QC::Job.new(
|
16
|
-
"id" => 1,
|
17
|
-
"details" => QC::OkJson.encode({"job" => "Class.method", "params" => []}),
|
18
|
-
"locked_at" => nil
|
19
|
-
)
|
20
|
-
assert_equal "Class.method", job.signature
|
21
|
-
end
|
22
|
-
|
23
|
-
test "method returns the class method" do
|
24
|
-
job = QC::Job.new(
|
25
|
-
"id" => 1,
|
26
|
-
"details" => QC::OkJson.encode({"job" => "Class.method", "params" => []}),
|
27
|
-
"locked_at" => nil
|
28
|
-
)
|
29
|
-
assert_equal "method", job.method
|
30
|
-
end
|
31
|
-
|
32
|
-
test "klass returns the class" do
|
33
|
-
class WhoHa; end
|
34
|
-
job = QC::Job.new(
|
35
|
-
"id" => 1,
|
36
|
-
"details" => QC::OkJson.encode({"job" => "WhoHa.method", "params" => []}),
|
37
|
-
"locked_at" => nil
|
38
|
-
)
|
39
|
-
assert_equal WhoHa, job.klass
|
40
|
-
end
|
41
|
-
|
42
|
-
test "klass returns the class when scoped to module" do
|
43
|
-
module Mod
|
44
|
-
class K
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
job = QC::Job.new(
|
49
|
-
"id" => 1,
|
50
|
-
"details" => QC::OkJson.encode({"job" => "Mod::K.method", "params" => []}),
|
51
|
-
"locked_at" => nil
|
52
|
-
)
|
53
|
-
assert_equal Mod::K, job.klass
|
54
|
-
end
|
55
|
-
|
56
|
-
test "params returns empty array when nil" do
|
57
|
-
job = QC::Job.new(
|
58
|
-
"id" => 1,
|
59
|
-
"details" => QC::OkJson.encode({"job" => "Mod::K.method", "params" => nil}),
|
60
|
-
"locked_at" => nil
|
61
|
-
)
|
62
|
-
assert_equal [], job.params
|
63
|
-
end
|
64
|
-
|
65
|
-
test "params returns 1 items when there is 1 param" do
|
66
|
-
job = QC::Job.new(
|
67
|
-
"id" => 1,
|
68
|
-
"details" => QC::OkJson.encode({"job" => "Mod::K.method", "params" => ["arg"]}),
|
69
|
-
"locked_at" => nil
|
70
|
-
)
|
71
|
-
assert_equal "arg", job.params
|
72
|
-
end
|
73
|
-
|
74
|
-
test "params retuns many items when there are many params" do
|
75
|
-
job = QC::Job.new(
|
76
|
-
"id" => 1,
|
77
|
-
"details" => QC::OkJson.encode({"job" => "Mod::K.method", "params" => ["arg","arg"]}),
|
78
|
-
"locked_at" => nil
|
79
|
-
)
|
80
|
-
assert_equal ["arg","arg"], job.params
|
81
|
-
end
|
82
|
-
end
|