super-poller 0.1.1 → 0.1.2
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/bin/scripts/queue_choose +17 -0
- data/bin/scripts/queue_copy +4 -0
- data/bin/scripts/queue_flush +3 -0
- data/bin/scripts/queue_grep +51 -0
- data/bin/scripts/queue_interactive_move +13 -0
- data/bin/scripts/queue_move +4 -0
- data/bin/scripts/queue_scan +3 -0
- data/lib/super_poller/aggregating_error_logger.rb +33 -0
- data/lib/super_poller/buffered_handler.rb +28 -0
- data/lib/super_poller/error_reporter.rb +12 -0
- data/lib/super_poller/handler.rb +22 -0
- data/lib/super_poller/none_blocking_poller.rb +13 -0
- data/lib/super_poller/poller.rb +24 -0
- data/lib/super_poller/queue_itterator.rb +30 -0
- data/lib/super_poller/queue_url.rb +18 -0
- data/lib/super_poller/router.rb +29 -0
- data/lib/super_poller/starling_queue.rb +20 -0
- data/lib/super_poller/test_case.rb +13 -0
- metadata +20 -2
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            require "super_poller"
         | 
| 2 | 
            +
            queue = SuperPoller::QueueUrl.parse(ARGV.shift).to_queue
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            memo = {:memo => Time.now.to_f}
         | 
| 5 | 
            +
            queue.push(memo)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            SuperPoller::NoneBlockingPoller.new(queue, lambda{|msg|
         | 
| 8 | 
            +
              skip = false
         | 
| 9 | 
            +
              begin
         | 
| 10 | 
            +
                exit if msg == memo
         | 
| 11 | 
            +
                p msg
         | 
| 12 | 
            +
                print "Kill? > "
         | 
| 13 | 
            +
                skip = gets =~ /^[Yy]/
         | 
| 14 | 
            +
              ensure
         | 
| 15 | 
            +
                queue.push(msg) unless skip or msg == memo
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            }).start!
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            require "super_poller"
         | 
| 2 | 
            +
            require 'optparse'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            options = {}
         | 
| 5 | 
            +
            opts = OptionParser.new do |opts|
         | 
| 6 | 
            +
              opts.banner = "Usage queue grep QUEUE_URL [options]"
         | 
| 7 | 
            +
              opts.on("-f STRING", "--ruby-filter STRING", "Set ruby filter") do |v|
         | 
| 8 | 
            +
                options[:ruby_filter] = v
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              opts.on("-a STRING", "--ruby-action STRING", "Set ruby action") do |v|
         | 
| 12 | 
            +
                options[:ruby_action] = v
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              opts.on("-d", "--delete", "Delete all matches") do |v|
         | 
| 16 | 
            +
                options[:ruby_action] = ":delete"
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              opts.on("-c QUEUE", "--copy QUEUE", "Copy all matches") do |v|
         | 
| 20 | 
            +
                options[:ruby_action] = "SuperPoller::QueueUrl.parse(#{v.to_s.inspect}).to_queue.push(msg)"
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              opts.on("-m QUEUE", "--move QUEUE", "Move all matches") do |v|
         | 
| 24 | 
            +
                options[:ruby_action] = "SuperPoller::QueueUrl.parse(#{v.to_s.inspect}).to_queue.push(msg); :delete"
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              opts.on("-t TYPE", "--message-type TYPE", "Select messages of a given type") do |v|
         | 
| 28 | 
            +
                options[:ruby_filter] = "#{v.to_s.inspect} == msg[:name].to_s rescue false"
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              opts.on_tail("-h", "--help", "Show this message") do
         | 
| 32 | 
            +
                puts opts
         | 
| 33 | 
            +
                exit 1
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            opts.parse!
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            unless queue_url = ARGV.shift
         | 
| 40 | 
            +
              puts opts
         | 
| 41 | 
            +
              exit 1
         | 
| 42 | 
            +
            end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            queue = SuperPoller::QueueUrl.parse(queue_url).to_queue
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            eval "def matcher_matches?(msg); #{ options[:ruby_filter] || "true" }; end"
         | 
| 47 | 
            +
            eval "def action(msg); #{ options[:ruby_action] || "p msg" }; end"
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            SuperPoller::QueueItterator.new(queue).each do |msg|
         | 
| 50 | 
            +
              action(msg) if matcher_matches? msg
         | 
| 51 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require "super_poller"
         | 
| 2 | 
            +
            queue_one = SuperPoller::QueueUrl.parse(ARGV.shift).to_queue
         | 
| 3 | 
            +
            queue_two = SuperPoller::QueueUrl.parse(ARGV.shift).to_queue
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            SuperPoller::QueueItterator.new(queue_one).each do |msg|
         | 
| 6 | 
            +
              p msg
         | 
| 7 | 
            +
              print "Move to #{queue_two}? > "
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              if gets =~ /^[Yy]/
         | 
| 10 | 
            +
                queue_two.push(msg)
         | 
| 11 | 
            +
                :delete
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            class SuperPoller::AggregatingErrorLogger
         | 
| 2 | 
            +
              def initialize(stats_file, queue)
         | 
| 3 | 
            +
                @stats_file, @queue = stats_file, queue
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def call(error, failed_message)
         | 
| 7 | 
            +
                update_error_queue(error, failed_message)
         | 
| 8 | 
            +
                update_error_stats(error, failed_message[:name] || :unknown)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            protected
         | 
| 12 | 
            +
              def update_error_queue(error, failed_message)
         | 
| 13 | 
            +
                error_class_name = error.class.name.to_sym
         | 
| 14 | 
            +
                error_description = {:class => error_class_name, :message => error.message}
         | 
| 15 | 
            +
                @queue.push(failed_message.merge(:error => error_description))
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def update_error_stats(error, message_name)
         | 
| 19 | 
            +
                stats = load_stats
         | 
| 20 | 
            +
                error_class_name = error.class.name.to_sym
         | 
| 21 | 
            +
                stats_for_name = (stats[message_name] ||= {})
         | 
| 22 | 
            +
                stats_for_name[error_class_name] ||= 0
         | 
| 23 | 
            +
                stats_for_name[error_class_name] += 1
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                File.open(@stats_file, "w") do |file|
         | 
| 26 | 
            +
                  file << YAML.dump(stats)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              def load_stats
         | 
| 31 | 
            +
                File.exists?(@stats_file) && YAML.load(File.read(@stats_file)) || {}
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            class SuperPoller::BufferedHandler < SuperPoller::Handler
         | 
| 2 | 
            +
              class << self
         | 
| 3 | 
            +
                def buffer_size(size)
         | 
| 4 | 
            +
                  @max_buffer_size = size
         | 
| 5 | 
            +
                end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def max_buffer_size
         | 
| 8 | 
            +
                  @max_buffer_size || []
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def initialize
         | 
| 13 | 
            +
                @buffer = []
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def call(msg)
         | 
| 17 | 
            +
                @buffer.push msg
         | 
| 18 | 
            +
                if @buffer.size >= self.class.max_buffer_size
         | 
| 19 | 
            +
                  handle_batch @buffer
         | 
| 20 | 
            +
                  @buffer = []
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def handle_batch(batch)
         | 
| 25 | 
            +
                raise NotImplementedError, "You must define a batch handler."
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            class SuperPoller::ErrorReporter
         | 
| 2 | 
            +
              def initialize(message_handler, error_handler = nil, &block)
         | 
| 3 | 
            +
                @message_handler = message_handler
         | 
| 4 | 
            +
                @error_handler = error_handler || block
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
              
         | 
| 7 | 
            +
              def call(*args)
         | 
| 8 | 
            +
                @message_handler.call(*args)
         | 
| 9 | 
            +
              rescue StandardError => e
         | 
| 10 | 
            +
                @error_handler.call(e, *args)
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            class SuperPoller::Handler
         | 
| 2 | 
            +
              autoload :TestCase, "super_poller/test_case"
         | 
| 3 | 
            +
              
         | 
| 4 | 
            +
              class << self
         | 
| 5 | 
            +
                def handles(*new_message_names)
         | 
| 6 | 
            +
                  @message_names = (message_names + new_message_names).uniq
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def message_names
         | 
| 10 | 
            +
                  @message_names || []
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              def can_handle?(message)
         | 
| 15 | 
            +
                self.class.message_names.include? message[:name].to_sym
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              def call(message)
         | 
| 19 | 
            +
                raise NotImplementedError, "You must define a call handler."
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            class SuperPoller::Poller
         | 
| 2 | 
            +
              def initialize(queue, message_handler)
         | 
| 3 | 
            +
                @message_handler, @queue = message_handler, queue
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def poll
         | 
| 7 | 
            +
                @message_handler.call(get_message)
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def start!
         | 
| 11 | 
            +
                poll while true
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            protected
         | 
| 15 | 
            +
              def get_message
         | 
| 16 | 
            +
                @queue.pop
         | 
| 17 | 
            +
              rescue Interrupt
         | 
| 18 | 
            +
                raise
         | 
| 19 | 
            +
              rescue Object => e
         | 
| 20 | 
            +
                STDERR.puts "Error while fetching from the queue: #{e.class}: #{e.message}"
         | 
| 21 | 
            +
                sleep 10
         | 
| 22 | 
            +
                retry
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            class SuperPoller::QueueItterator
         | 
| 2 | 
            +
              def initialize(queue)
         | 
| 3 | 
            +
                @queue = queue
         | 
| 4 | 
            +
              end
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def each(&block)
         | 
| 7 | 
            +
                @memo = {:memo => Time.now.to_f}
         | 
| 8 | 
            +
                @queue.push @memo
         | 
| 9 | 
            +
                while @memo
         | 
| 10 | 
            +
                  begin
         | 
| 11 | 
            +
                    break unless msg = @queue.fetch
         | 
| 12 | 
            +
                    if msg == @memo
         | 
| 13 | 
            +
                      msg = @memo = nil
         | 
| 14 | 
            +
                    else
         | 
| 15 | 
            +
                      msg = nil if :delete == block.call(msg)
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  ensure
         | 
| 18 | 
            +
                    @queue.push msg if msg
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              ensure
         | 
| 22 | 
            +
                destroy_the_memo
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def destroy_the_memo
         | 
| 26 | 
            +
                while @memo and msg = @queue.fetch and msg != @memo
         | 
| 27 | 
            +
                  @queue.push(msg)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            require "uri"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class SuperPoller::QueueUrl < URI::Generic
         | 
| 4 | 
            +
              def self.parse(url)
         | 
| 5 | 
            +
                url = "starling://localhost:22122/#{url}" if url =~ /^[a-zA-Z0-9_-]+$/
         | 
| 6 | 
            +
                new(*URI.parse(url).send(:component_ary))
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def to_queue
         | 
| 10 | 
            +
                raise URI::InvalidURIError unless respond_to? "to_#{scheme}_queue"
         | 
| 11 | 
            +
                send("to_#{scheme}_queue")
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            protected
         | 
| 15 | 
            +
              def to_starling_queue
         | 
| 16 | 
            +
                SuperPoller::StarlingQueue.new(path, "#{host}:#{port}")
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            class SuperPoller::Router
         | 
| 2 | 
            +
              RoutingError = Class.new(Exception)
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              def initialize()
         | 
| 5 | 
            +
                @handlers = []
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def add_handler(handler)
         | 
| 9 | 
            +
                @handlers.push handler
         | 
| 10 | 
            +
                @handlers.uniq!
         | 
| 11 | 
            +
                self
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              alias << add_handler
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def call(message)
         | 
| 17 | 
            +
                handler = best_handler_for_message(message)
         | 
| 18 | 
            +
                handler.call(message[:body])
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            protected
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              def best_handler_for_message(messsage)
         | 
| 24 | 
            +
                @handlers.each do |handler|
         | 
| 25 | 
            +
                  return handler if handler.can_handle? messsage
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                raise RoutingError, "No handler found"
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require "starling"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class SuperPoller::StarlingQueue
         | 
| 4 | 
            +
              def initialize(queue_name, *args)
         | 
| 5 | 
            +
                @queue_name = queue_name.to_s
         | 
| 6 | 
            +
                @queue = Starling.new(*args)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def pop
         | 
| 10 | 
            +
                @queue.get(@queue_name)
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def push(v)
         | 
| 14 | 
            +
                @queue.set(@queue_name, v)
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def fetch
         | 
| 18 | 
            +
                @queue.fetch(@queue_name)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            class SuperPoller::Handler::TestCase < (defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              def handler
         | 
| 4 | 
            +
                @handler ||= self.class.name.gsub(/Test$/, "").constantize.new
         | 
| 5 | 
            +
              end
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              def self.should_handle(name)
         | 
| 8 | 
            +
                should "handle a #{name.inspect} message" do
         | 
| 9 | 
            +
                  assert handler.can_handle?(:name => name)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version | |
| 5 5 | 
             
              segments: 
         | 
| 6 6 | 
             
              - 0
         | 
| 7 7 | 
             
              - 1
         | 
| 8 | 
            -
              -  | 
| 9 | 
            -
              version: 0.1. | 
| 8 | 
            +
              - 2
         | 
| 9 | 
            +
              version: 0.1.2
         | 
| 10 10 | 
             
            platform: ruby
         | 
| 11 11 | 
             
            authors: 
         | 
| 12 12 | 
             
            - Tom Lea
         | 
| @@ -29,6 +29,24 @@ extra_rdoc_files: [] | |
| 29 29 |  | 
| 30 30 | 
             
            files: 
         | 
| 31 31 | 
             
            - bin/queue
         | 
| 32 | 
            +
            - bin/scripts/queue_choose
         | 
| 33 | 
            +
            - bin/scripts/queue_copy
         | 
| 34 | 
            +
            - bin/scripts/queue_flush
         | 
| 35 | 
            +
            - bin/scripts/queue_grep
         | 
| 36 | 
            +
            - bin/scripts/queue_interactive_move
         | 
| 37 | 
            +
            - bin/scripts/queue_move
         | 
| 38 | 
            +
            - bin/scripts/queue_scan
         | 
| 39 | 
            +
            - lib/super_poller/aggregating_error_logger.rb
         | 
| 40 | 
            +
            - lib/super_poller/buffered_handler.rb
         | 
| 41 | 
            +
            - lib/super_poller/error_reporter.rb
         | 
| 42 | 
            +
            - lib/super_poller/handler.rb
         | 
| 43 | 
            +
            - lib/super_poller/none_blocking_poller.rb
         | 
| 44 | 
            +
            - lib/super_poller/poller.rb
         | 
| 45 | 
            +
            - lib/super_poller/queue_itterator.rb
         | 
| 46 | 
            +
            - lib/super_poller/queue_url.rb
         | 
| 47 | 
            +
            - lib/super_poller/router.rb
         | 
| 48 | 
            +
            - lib/super_poller/starling_queue.rb
         | 
| 49 | 
            +
            - lib/super_poller/test_case.rb
         | 
| 32 50 | 
             
            - lib/super_poller.rb
         | 
| 33 51 | 
             
            - test/aggregating_error_logger_test.rb
         | 
| 34 52 | 
             
            - test/buffered_handler_test.rb
         |