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
         |