queue_classic 0.2.0 → 0.2.1

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.
@@ -6,7 +6,11 @@ module QC
6
6
  end
7
7
 
8
8
  def enqueue(job,*params)
9
- queue.enqueue(job,params)
9
+ if job.respond_to?(:details) and job.respond_to?(:params)
10
+ queue.enqueue(job.signature, (job.params || []))
11
+ else
12
+ queue.enqueue(job,params)
13
+ end
10
14
  end
11
15
 
12
16
  def dequeue
@@ -17,6 +21,10 @@ module QC
17
21
  queue.delete(job)
18
22
  end
19
23
 
24
+ def delete_all
25
+ queue.delete_all
26
+ end
27
+
20
28
  def queue_length
21
29
  queue.length
22
30
  end
@@ -26,7 +34,11 @@ module QC
26
34
  method = job.method
27
35
  params = job.params
28
36
 
29
- klass.send(method,params)
37
+ if params.class == Array
38
+ klass.send(method,*params)
39
+ else
40
+ klass.send(method,params)
41
+ end
30
42
  end
31
43
 
32
44
  def logging_enabled?
@@ -3,9 +3,6 @@ module QC
3
3
 
4
4
  def initialize(args={})
5
5
  @db_string = args[:database]
6
- @connection = connection
7
- execute("SET client_min_messages TO 'warning'")
8
- with_log("setup PG LISTEN") { execute("LISTEN jobs") }
9
6
  end
10
7
 
11
8
  def <<(details)
@@ -18,7 +15,7 @@ module QC
18
15
  end
19
16
 
20
17
  def delete(job)
21
- with_log("deleting job #{job.id}") { execute("DELETE FROM jobs WHERE id = #{job.id}") }
18
+ execute("DELETE FROM jobs WHERE id = #{job.id}")
22
19
  job
23
20
  end
24
21
 
@@ -28,7 +25,7 @@ module QC
28
25
 
29
26
  def lock_head
30
27
  job = nil
31
- @connection.transaction do
28
+ connection.transaction do
32
29
  if job = find_one {"SELECT * FROM jobs WHERE locked_at IS NULL ORDER BY id ASC LIMIT 1 FOR UPDATE"}
33
30
  execute("UPDATE jobs SET locked_at = (CURRENT_TIMESTAMP) WHERE id = #{job.id} AND locked_at IS NULL")
34
31
  end
@@ -40,37 +37,32 @@ module QC
40
37
  if job = lock_head
41
38
  job
42
39
  else
43
- @connection.wait_for_notify {|e,p,msg| job = lock_head if msg == "new-job" }
40
+ execute("LISTEN jobs")
41
+ connection.wait_for_notify {|e,p,msg| job = lock_head if msg == "new-job" }
44
42
  job
45
43
  end
46
44
  end
47
45
 
48
46
  def each
49
47
  execute("SELECT * FROM jobs ORDER BY id ASC").each do |r|
50
- yield(JSON.parse(r["details"]))
48
+ yield Job.new(r)
51
49
  end
52
50
  end
53
51
 
54
52
  def execute(sql)
55
- @connection.async_exec(sql)
53
+ connection.exec(sql)
56
54
  end
57
55
 
58
56
  def find_one
59
57
  res = execute(yield)
60
58
  if res.count > 0
61
- res.map do |r|
62
- Job.new(
63
- "id" => r["id"],
64
- "details" => JSON.parse( r["details"]),
65
- "locked_at" => r["locked_at"]
66
- )
67
- end.pop
59
+ res.map {|r| Job.new(r)}.pop
68
60
  end
69
61
  end
70
62
 
71
63
  def connection
72
64
  db_params = URI.parse(@db_string)
73
- if db_params.scheme == "postgres"
65
+ @connection ||= if db_params.scheme == "postgres"
74
66
  PGconn.connect(
75
67
  :dbname => db_params.path.gsub("/",""),
76
68
  :user => db_params.user,
@@ -82,19 +74,5 @@ module QC
82
74
  end
83
75
  end
84
76
 
85
- def with_log(msg)
86
- res = yield
87
- if QC.logging_enabled?
88
- log(msg)
89
- log(res.cmd_status) if res.respond_to?(:cmd_status)
90
- log(res.result_error_message) if res.respond_to?(:result_error_message)
91
- end
92
- res
93
- end
94
-
95
- def log(msg)
96
- puts "| \t" + msg
97
- end
98
-
99
77
  end
100
78
  end
@@ -4,19 +4,24 @@ module QC
4
4
 
5
5
  def initialize(args={})
6
6
  @id = args["id"]
7
- @details = args["details"]
7
+ @details = JSON.parse(args["details"])
8
8
  @locked_at = args["locked_at"]
9
9
  end
10
10
 
11
11
  def klass
12
- Kernel.const_get(details["job"].split(".").first)
12
+ eval(details["job"].split(".").first)
13
13
  end
14
14
 
15
15
  def method
16
16
  details["job"].split(".").last
17
17
  end
18
18
 
19
+ def signature
20
+ details["job"]
21
+ end
22
+
19
23
  def params
24
+ return [] unless details["params"]
20
25
  params = details["params"]
21
26
  if params.length == 1
22
27
  return params[0]
@@ -19,6 +19,10 @@ module QC
19
19
  @data.delete(job)
20
20
  end
21
21
 
22
+ def delete_all
23
+ @data.each {|j| delete(j) }
24
+ end
25
+
22
26
  def length
23
27
  @data.count
24
28
  end
@@ -1,11 +1,11 @@
1
1
  # Queue Classic
2
- __Beta 0.2.0__
2
+ __Beta 0.2.1__
3
3
 
4
- __Queue Classic 0.2.0 is in Beta.__ I have been using this library with 30-50 Heroku workers and have had great results. However, your mileage may vary.
4
+ __Queue Classic 0.2.1 is in Beta.__ I have been using this library with 30-50 Heroku workers and have had great results. However, your mileage may vary.
5
5
 
6
6
  I am using this in production applications and plan to maintain and support this library for a long time.
7
7
 
8
- Queue Classic is an alternative queueing library for Ruby apps (Rails, Sinatra, Etc...) Queue Classic features __asynchronous__ job polling, database maintained locks and
8
+ Queue Classic is an alternative queueing library for Ruby apps (Rails, Sinatra, Etc...) Queue Classic features a blocking dequeue, database maintained locks and
9
9
  no ridiculous dependencies. As a matter of fact, Queue Classic only requires the __pg__ and __json__.
10
10
 
11
11
  ## Installation
@@ -1,14 +1,31 @@
1
1
  require File.expand_path("../helper.rb", __FILE__)
2
2
 
3
- class ApiTest < MiniTest::Unit::TestCase
4
- include DatabaseHelpers
3
+ context "QC::Api" do
4
+ setup { clean_database }
5
5
 
6
- def test_enqueue_takes_a_job
7
- clean_database
6
+ test "enqueue takes a job without params" do
7
+ QC.enqueue "Notifier.send"
8
8
 
9
- assert_equal 0, QC.queue_length
10
- res = QC.enqueue "Notifier.send", {}
11
- assert_equal 1, QC.queue_length
9
+ job = QC.dequeue
10
+ assert_equal({"job" => "Notifier.send", "params" => [] }, job.details)
12
11
  end
12
+
13
+ test "enqueue takes a hash" do
14
+ QC.enqueue "Notifier.send", {:arg => 1}
15
+
16
+ job = QC.dequeue
17
+ assert_equal({"job" => "Notifier.send", "params" => [{"arg" => 1}] }, job.details)
18
+ end
19
+
20
+ test "enqueue takes a job" do
21
+ h = {"id" => 1, "details" => {"job" => 'Notifier.send'}.to_json, "locked_at" => nil}
22
+ job = QC::Job.new(h)
23
+ QC.enqueue(job)
24
+
25
+ job = QC.dequeue
26
+ assert_equal({"job" => "Notifier.send", "params" => []}, job.details)
27
+ end
28
+
29
+
13
30
  end
14
31
 
@@ -47,8 +47,10 @@ class DurableArrayTest < MiniTest::Unit::TestCase
47
47
  job = array.first
48
48
 
49
49
  assert_equal( {"job" => "one"}, job.details)
50
+
51
+ assert_equal(1,array.count)
50
52
  array.delete(job)
51
- assert_nil array.first
53
+ assert_equal(0,array.count)
52
54
  end
53
55
 
54
56
  def test_delete_returns_job_after_delete
@@ -61,7 +63,6 @@ class DurableArrayTest < MiniTest::Unit::TestCase
61
63
  assert_equal({"job" => "one"}, job.details)
62
64
 
63
65
  res = array.delete(job)
64
- assert_nil(array.first)
65
66
  assert_equal({"job" => "one"}, res.details)
66
67
  end
67
68
 
@@ -72,7 +73,7 @@ class DurableArrayTest < MiniTest::Unit::TestCase
72
73
  array << {"job" => "one"}
73
74
  array << {"job" => "two"}
74
75
  results = []
75
- array.each {|v| results << v}
76
+ array.each {|v| results << v.details}
76
77
  assert_equal([{"job" => "one"},{"job" => "two"}], results)
77
78
  end
78
79
 
@@ -16,3 +16,19 @@ def set_data_store(store=nil)
16
16
  )
17
17
  )
18
18
  end
19
+
20
+ def context(*args, &block)
21
+ return super unless (name = args.first) && block
22
+ klass = Class.new(MiniTest::Unit::TestCase) do
23
+ def self.test(name, &block)
24
+ define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
25
+ end
26
+ def self.xtest(*args) end
27
+ def self.setup(&block) define_method(:setup, &block) end
28
+ def self.teardown(&block) define_method(:teardown, &block) end
29
+ end
30
+ (class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
31
+
32
+ klass.send :include, DatabaseHelpers
33
+ klass.class_eval &block
34
+ end
@@ -0,0 +1,82 @@
1
+ require File.expand_path("../helper.rb", __FILE__)
2
+
3
+ context "QC::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" => {:job => "Class.method", :params => []}.to_json,
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" => {:job => "Class.method", :params => []}.to_json,
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" => {:job => "WhoHa.method", :params => []}.to_json,
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" => {:job => "Mod::K.method", :params => []}.to_json,
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" => {:job => "Mod::K.method", :params => nil}.to_json,
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" => {:job => "Mod::K.method", :params => ["arg"]}.to_json,
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" => {:job => "Mod::K.method", :params => ["arg","arg"]}.to_json,
78
+ "locked_at" => nil
79
+ )
80
+ assert_equal ["arg","arg"], job.params
81
+ end
82
+ end
@@ -19,4 +19,15 @@ class QueueTest < MiniTest::Unit::TestCase
19
19
  assert_equal 1, QC::Queue.instance.length
20
20
  end
21
21
 
22
+ def test_queue_delete_all
23
+ QC::Queue.instance.setup :data_store => []
24
+
25
+ QC::Queue.instance.enqueue "job","params"
26
+ QC::Queue.instance.enqueue "job","params"
27
+
28
+ assert_equal 2, QC::Queue.instance.length
29
+ QC::Queue.instance.delete_all
30
+ assert_equal 0, QC::Queue.instance.length
31
+ end
32
+
22
33
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 0
9
- version: 0.2.0
8
+ - 1
9
+ version: 0.2.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ryan Smith
@@ -55,7 +55,6 @@ extra_rdoc_files: []
55
55
 
56
56
  files:
57
57
  - readme.markdown
58
- - lib/notifier.rb
59
58
  - lib/queue_classic/api.rb
60
59
  - lib/queue_classic/durable_array.rb
61
60
  - lib/queue_classic/job.rb
@@ -67,6 +66,7 @@ files:
67
66
  - test/database_helpers.rb
68
67
  - test/durable_array_test.rb
69
68
  - test/helper.rb
69
+ - test/job_test.rb
70
70
  - test/queue_test.rb
71
71
  - test/worker_test.rb
72
72
  has_rdoc: true
@@ -104,5 +104,6 @@ summary: Queue Classic is an alternative queueing library for Ruby apps (Rails,
104
104
  test_files:
105
105
  - test/api_test.rb
106
106
  - test/durable_array_test.rb
107
+ - test/job_test.rb
107
108
  - test/queue_test.rb
108
109
  - test/worker_test.rb
@@ -1,7 +0,0 @@
1
- class Notifier
2
-
3
- def self.deliver(msg)
4
- `say #{msg}`
5
- end
6
-
7
- end