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
|