super-poller 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|