super-poller 0.1.3 → 0.2.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.
- data/lib/super_poller.rb +2 -0
- data/lib/super_poller/poller.rb +3 -3
- data/lib/super_poller/retry_wrapper.rb +21 -0
- data/lib/super_poller/stats.rb +74 -0
- data/test/retry_wrapper_test.rb +27 -0
- metadata +6 -3
data/lib/super_poller.rb
CHANGED
@@ -9,4 +9,6 @@ module SuperPoller
|
|
9
9
|
autoload :NoneBlockingPoller, "super_poller/none_blocking_poller"
|
10
10
|
autoload :QueueUrl, "super_poller/queue_url"
|
11
11
|
autoload :QueueItterator, "super_poller/queue_itterator"
|
12
|
+
autoload :Stats, "super_poller/stats"
|
13
|
+
autoload :RetryWrapper, "super_poller/retry_wrapper"
|
12
14
|
end
|
data/lib/super_poller/poller.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
class SuperPoller::Poller
|
2
|
-
def initialize(queue, message_handler)
|
3
|
-
@message_handler, @queue = message_handler, queue
|
2
|
+
def initialize(queue, message_handler, sleep_time = 1)
|
3
|
+
@message_handler, @queue, @sleep_time = message_handler, queue, sleep_time
|
4
4
|
end
|
5
5
|
|
6
6
|
def poll
|
@@ -16,7 +16,7 @@ protected
|
|
16
16
|
@queue.pop
|
17
17
|
rescue => e
|
18
18
|
STDERR.puts "Error while fetching from the queue: #{e.class}: #{e.message}"
|
19
|
-
sleep
|
19
|
+
sleep @sleep_time
|
20
20
|
retry
|
21
21
|
end
|
22
22
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class SuperPoller::RetryWrapper
|
2
|
+
def initialize(&block)
|
3
|
+
@builder = block
|
4
|
+
end
|
5
|
+
|
6
|
+
protected
|
7
|
+
def wrapped_queue
|
8
|
+
@queue ||= @builder.call
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset_wrapped_queue!
|
12
|
+
@queue = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(*args)
|
16
|
+
wrapped_queue.send(*args)
|
17
|
+
rescue RuntimeError => e
|
18
|
+
reset_wrapped_queue!
|
19
|
+
raise
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class SuperPoller::Stats
|
2
|
+
def initialize(router, out = STDERR, interval = 60)
|
3
|
+
@router = router
|
4
|
+
@out = out
|
5
|
+
@semaphore = Mutex.new
|
6
|
+
@interval = interval
|
7
|
+
reset
|
8
|
+
ensure_worker_is_running
|
9
|
+
end
|
10
|
+
|
11
|
+
def ensure_worker_is_running
|
12
|
+
return if @worker && @worker.alive?
|
13
|
+
@worker.join if @worker
|
14
|
+
|
15
|
+
@worker = Thread.start{
|
16
|
+
Thread.abort_on_exception = true
|
17
|
+
while true
|
18
|
+
flush
|
19
|
+
sleep(@interval)
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(msg)
|
25
|
+
ensure_worker_is_running
|
26
|
+
@semaphore.synchronize do
|
27
|
+
begin
|
28
|
+
name = msg[:name]
|
29
|
+
@counts[name] += 1
|
30
|
+
start_time = Time.now
|
31
|
+
@router.call(msg)
|
32
|
+
|
33
|
+
ensure
|
34
|
+
end_time = Time.now
|
35
|
+
duration = end_time.to_f - start_time.to_f
|
36
|
+
@durations[name] << duration
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def reset
|
44
|
+
@counts = Hash.new(0)
|
45
|
+
@durations = Hash.new{|h,k| h[k] = []}
|
46
|
+
end
|
47
|
+
|
48
|
+
def flush
|
49
|
+
@semaphore.synchronize do
|
50
|
+
if use_atomic_write?
|
51
|
+
f = Tempfile.open("queue_stats", File.dirname(@out) )
|
52
|
+
else
|
53
|
+
f = @out
|
54
|
+
end
|
55
|
+
|
56
|
+
f.puts Time.now.to_s
|
57
|
+
@counts.each do |name, count|
|
58
|
+
durations = @durations[name]
|
59
|
+
f.puts "#{name}: #{count} messages, mean: #{durations.sum/count}s, min: #{durations.min}s, max: #{durations.max}s"
|
60
|
+
end
|
61
|
+
|
62
|
+
if use_atomic_write?
|
63
|
+
f.close
|
64
|
+
File.unlink(@out) if File.exists?(@out)
|
65
|
+
File.link(f.path, @out)
|
66
|
+
end
|
67
|
+
reset
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def use_atomic_write?
|
72
|
+
! @out.is_a?( IO )
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
+
|
3
|
+
class RetryWrapperTest < Test::Unit::TestCase
|
4
|
+
include SuperPoller
|
5
|
+
|
6
|
+
context "A RetryWrapper wraped around a queue" do
|
7
|
+
setup do
|
8
|
+
@queue_factory = stub(:queue_factory)
|
9
|
+
@queue = stub("Queue", :pop => "Fish")
|
10
|
+
@raiser_queue = stub("Queue")
|
11
|
+
@raiser_queue.stubs(:pop).raises(RuntimeError)
|
12
|
+
@wrapper = RetryWrapper.new{ @queue_factory.build }
|
13
|
+
end
|
14
|
+
|
15
|
+
should "delegate pop to a new queue from the queue factory" do
|
16
|
+
@queue_factory.expects(:build).returns(@queue).once
|
17
|
+
assert_equal "Fish", @wrapper.pop
|
18
|
+
assert_equal "Fish", @wrapper.pop
|
19
|
+
end
|
20
|
+
|
21
|
+
should "create a new queue using the factory if the first one raises" do
|
22
|
+
@queue_factory.expects(:build).returns(@raiser_queue).twice
|
23
|
+
assert_raise(RuntimeError){ @wrapper.pop }
|
24
|
+
assert_raise(RuntimeError){ @wrapper.pop }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Tom Lea
|
@@ -44,8 +44,10 @@ files:
|
|
44
44
|
- lib/super_poller/poller.rb
|
45
45
|
- lib/super_poller/queue_itterator.rb
|
46
46
|
- lib/super_poller/queue_url.rb
|
47
|
+
- lib/super_poller/retry_wrapper.rb
|
47
48
|
- lib/super_poller/router.rb
|
48
49
|
- lib/super_poller/starling_queue.rb
|
50
|
+
- lib/super_poller/stats.rb
|
49
51
|
- lib/super_poller/test_case.rb
|
50
52
|
- lib/super_poller.rb
|
51
53
|
- test/aggregating_error_logger_test.rb
|
@@ -53,6 +55,7 @@ files:
|
|
53
55
|
- test/error_reporter_test.rb
|
54
56
|
- test/handler_test.rb
|
55
57
|
- test/poller_test.rb
|
58
|
+
- test/retry_wrapper_test.rb
|
56
59
|
- test/router_test.rb
|
57
60
|
- test/starling_queue_test.rb
|
58
61
|
- test/test_helper.rb
|