boardintel_frenzy_bunnies 0.0.17-java

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.
Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-version +1 -0
  4. data/Gemfile +4 -0
  5. data/Guardfile +19 -0
  6. data/LICENSE +22 -0
  7. data/README.md +165 -0
  8. data/Rakefile +2 -0
  9. data/bin/frenzy_bunnies +6 -0
  10. data/examples/feed.rb +20 -0
  11. data/examples/feed_worker.rb +33 -0
  12. data/examples/feed_workers_bin.rb +21 -0
  13. data/fb-cap.png +0 -0
  14. data/frenzy_bunnies.gemspec +27 -0
  15. data/lib/frenzy_bunnies/cli.rb +29 -0
  16. data/lib/frenzy_bunnies/context.rb +40 -0
  17. data/lib/frenzy_bunnies/handlers/maxretry.rb +199 -0
  18. data/lib/frenzy_bunnies/handlers/oneshot.rb +31 -0
  19. data/lib/frenzy_bunnies/health/collector.rb +21 -0
  20. data/lib/frenzy_bunnies/health/providers/jvm.rb +43 -0
  21. data/lib/frenzy_bunnies/health.rb +10 -0
  22. data/lib/frenzy_bunnies/queue_factory.rb +23 -0
  23. data/lib/frenzy_bunnies/version.rb +3 -0
  24. data/lib/frenzy_bunnies/web/public/css/bootstrap.min.css +9 -0
  25. data/lib/frenzy_bunnies/web/public/img/bunny16.png +0 -0
  26. data/lib/frenzy_bunnies/web/public/img/bunny32.png +0 -0
  27. data/lib/frenzy_bunnies/web/public/index.html +225 -0
  28. data/lib/frenzy_bunnies/web/public/js/app.coffee +90 -0
  29. data/lib/frenzy_bunnies/web/public/js/app.js +202 -0
  30. data/lib/frenzy_bunnies/web/public/js/backbone-min.js +40 -0
  31. data/lib/frenzy_bunnies/web/public/js/bootstrap.js +2027 -0
  32. data/lib/frenzy_bunnies/web/public/js/bootstrap.min.js +6 -0
  33. data/lib/frenzy_bunnies/web/public/js/jquery-1.8.0.min.js +2 -0
  34. data/lib/frenzy_bunnies/web/public/js/jquery.filesize.js +52 -0
  35. data/lib/frenzy_bunnies/web/public/js/jquery.timeago.js +152 -0
  36. data/lib/frenzy_bunnies/web/public/js/underscore-min.js +32 -0
  37. data/lib/frenzy_bunnies/web.rb +51 -0
  38. data/lib/frenzy_bunnies/worker.rb +105 -0
  39. data/lib/frenzy_bunnies.rb +15 -0
  40. data/spec/frenzy_bunnies/worker_spec.rb +117 -0
  41. data/spec/spec_helper.rb +35 -0
  42. metadata +184 -0
@@ -0,0 +1,51 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ class FrenzyBunnies::Web < Sinatra::Base
5
+ configure do
6
+ # disable logging
7
+ set :public_folder, File.expand_path('web/public', File.dirname(__FILE__))
8
+ end
9
+
10
+ before do
11
+ content_type 'application/json'
12
+ end
13
+
14
+ not_found do
15
+ 'Cant find that, sorry.'
16
+ end
17
+
18
+ error do
19
+ 'Oops. There was an error - ' + env['sinatra.error'].name
20
+ end
21
+
22
+ get '/ping' do
23
+ 'ok'
24
+ end
25
+
26
+ get '/health' do
27
+ settings.health_collector.collect.to_json
28
+ end
29
+
30
+ get '/stats' do
31
+ jobs.map do |klass|
32
+ { :name => klass.name,
33
+ :stats => klass.jobs_stats }
34
+ end.to_json
35
+ end
36
+
37
+ get '/' do
38
+ redirect '/index.html'
39
+ end
40
+
41
+ def self.run_with(jobs, opts={})
42
+ set :jobs, (jobs || [])
43
+ set :health_collector, FrenzyBunnies::Health::Collector.new({:jvm => {:threadfilter => opts[:threadfilter]}})
44
+ @logger = opts[:logger]
45
+ @logger.info "* running web dashboard bound to #{opts[:host]} on port #{opts[:port]}."
46
+ Rack::Handler::WEBrick.run self, :Host => opts[:host], :Port => opts[:port], :Logger => WEBrick::Log.new("/dev/null"), :AccessLog => [nil, nil]
47
+ end
48
+ def jobs
49
+ settings.jobs
50
+ end
51
+ end
@@ -0,0 +1,105 @@
1
+ require 'atomic'
2
+
3
+ module FrenzyBunnies::Worker
4
+ def ack!
5
+ true
6
+ end
7
+
8
+ def reject!
9
+ false
10
+ end
11
+
12
+ def work
13
+ end
14
+
15
+ def self.included(base)
16
+ base.extend ClassMethods
17
+ end
18
+
19
+ module ClassMethods
20
+
21
+ def from_queue(q, opts={})
22
+ @queue_name = q
23
+ @queue_opts = opts
24
+ end
25
+
26
+ def start(context)
27
+ @jobs_stats = { :failed => Atomic.new(0), :passed => Atomic.new(0) }
28
+ @working_since = Time.now
29
+
30
+ @logger = context.logger
31
+
32
+ @queue_opts[:prefetch] ||= 10
33
+ @queue_opts[:durable] ||= false
34
+ @queue_opts[:timeout_job_after] = 5 if @queue_opts[:timeout_job_after].nil?
35
+ @queue_opts[:handler] ||= FrenzyBunnies::Handlers::Oneshot
36
+
37
+ if @queue_opts[:threads]
38
+ @thread_pool = MarchHare::ThreadPools.fixed_of_size(@queue_opts[:threads])
39
+ else
40
+ @thread_pool = MarchHare::ThreadPools.dynamically_growing
41
+ end
42
+
43
+ q = context.queue_factory.build_queue(@queue_name, @queue_opts)
44
+
45
+ say "#{@queue_opts[:threads]} with #{@queue_opts[:prefetch]} prefetch on <#{@queue_name}>."
46
+
47
+ q.subscribe(:ack => true, :blocking => false) do |headers, msg|
48
+ @thread_pool.submit do
49
+ worker = new
50
+ handler = @queue_opts[:handler].new(headers.channel, q, @logger, { queue_options: @queue_opts })
51
+ begin
52
+ Timeout::timeout(@queue_opts[:timeout_job_after]) do
53
+ if worker.work(msg)
54
+ handler.acknowledge(headers, msg)
55
+ incr! :passed
56
+ else
57
+ handler.reject(headers, msg)
58
+ incr! :failed
59
+ error "REJECTED", msg
60
+ end
61
+ end
62
+ rescue Timeout::Error
63
+ handler.timeout(headers, msg)
64
+ incr! :failed
65
+ error "TIMEOUT #{@queue_opts[:timeout_job_after]}s", msg
66
+ rescue
67
+ handler.reject(headers, msg)
68
+ incr! :failed
69
+ error "ERROR #{$!}", msg
70
+ end
71
+ end
72
+ end
73
+ say "workers up."
74
+ end
75
+
76
+ def stop
77
+ say "stopping"
78
+ @thread_pool.shutdown_now
79
+ say "pool shutdown"
80
+ # @s.cancel #for some reason when the channel socket is broken, this is holding the process up and we're zombie.
81
+ say "stopped"
82
+ end
83
+
84
+ def queue_opts
85
+ @queue_opts
86
+ end
87
+
88
+ def jobs_stats
89
+ Hash[ @jobs_stats.map{ |k,v| [k, v.value] } ].merge({ :since => @working_since.to_i })
90
+ end
91
+ private
92
+ def say(text)
93
+ @logger.info "[#{self.name}] #{text}"
94
+ end
95
+
96
+ def error(text, msg)
97
+ @logger.error "[#{self.name}] #{text} <#{msg}>"
98
+ end
99
+
100
+ def incr!(what)
101
+ @jobs_stats[what].update { |v| v + 1 }
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,15 @@
1
+ require 'march_hare'
2
+ require 'timeout'
3
+
4
+ module FrenzyBunnies
5
+ end
6
+
7
+
8
+ require "frenzy_bunnies/version"
9
+ require 'frenzy_bunnies/health'
10
+ require 'frenzy_bunnies/queue_factory'
11
+ require 'frenzy_bunnies/context'
12
+ require 'frenzy_bunnies/handlers/oneshot'
13
+ require 'frenzy_bunnies/worker'
14
+ require 'frenzy_bunnies/web'
15
+
@@ -0,0 +1,117 @@
1
+ require 'spec_helper'
2
+ require 'frenzy_bunnies'
3
+
4
+ class DummyWorker
5
+ include FrenzyBunnies::Worker
6
+ from_queue 'new.feeds'
7
+
8
+ def work(msg)
9
+ end
10
+ end
11
+
12
+ class CustomWorker
13
+ include FrenzyBunnies::Worker
14
+ from_queue 'new.feeds', :prefetch => 20, :durable => true, :timeout_job_after => 13, :threads => 25
15
+
16
+ def work(msg)
17
+ end
18
+ end
19
+
20
+ def with_test_queuefactory(ctx, ack=true, msg=nil, nowork=false)
21
+ qf = Object.new
22
+ q = Object.new
23
+ s = Object.new
24
+ hdr = Object.new
25
+ mock(qf).build_queue(anything, anything) { q }
26
+ mock(q).subscribe(anything){ s }
27
+
28
+ mock(s).each(anything) { |h,b| b.call(hdr, msg) unless nowork }
29
+ mock(hdr).ack{true} if !nowork && ack
30
+ mock(hdr).reject{true} if !nowork && !ack
31
+
32
+ mock(ctx).queue_factory { qf } # should return our own
33
+ end
34
+
35
+ describe FrenzyBunnies::Worker do
36
+ it "should start with a clean slate" do
37
+ # check stats, default configuration
38
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
39
+ with_test_queuefactory(ctx, nil, nil, true)
40
+
41
+
42
+ DummyWorker.start(ctx)
43
+ DummyWorker.jobs_stats[:failed].must_equal 0
44
+ DummyWorker.jobs_stats[:passed].must_equal 0
45
+ q = DummyWorker.queue_opts
46
+ q.must_equal({:prefetch=>10, :durable=>false, :timeout_job_after=>5})
47
+
48
+ end
49
+ it "should respond to configuration tweaks" do
50
+ # check that all params are changed
51
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
52
+ with_test_queuefactory(ctx, nil, nil, true)
53
+
54
+ CustomWorker.start(ctx)
55
+ CustomWorker.jobs_stats[:failed].must_equal 0
56
+ CustomWorker.jobs_stats[:passed].must_equal 0
57
+ q = CustomWorker.queue_opts
58
+ q.must_equal({:prefetch=>20, :durable=>true, :timeout_job_after=>13, :threads=>25})
59
+ end
60
+ it "should stop when asked to" do
61
+ # validate that a worker stops
62
+ # check stats, default configuration
63
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
64
+ with_test_queuefactory(ctx, nil, nil, true)
65
+
66
+
67
+ DummyWorker.start(ctx)
68
+ DummyWorker.stop
69
+ end
70
+ it "should be passed a message to work on" do
71
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
72
+ with_test_queuefactory(ctx, true, "work!")
73
+
74
+ any_instance_of(DummyWorker){ |w| mock(w).work("work!"){ true } }
75
+ DummyWorker.start(ctx)
76
+ end
77
+ it "should acknowledge a unit of work when worker succeeds" do
78
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
79
+ with_test_queuefactory(ctx)
80
+
81
+ any_instance_of(DummyWorker){ |w| mock(w).work(anything){ true } }
82
+ DummyWorker.start(ctx)
83
+ DummyWorker.jobs_stats[:passed].must_equal 1
84
+ DummyWorker.jobs_stats[:failed].must_equal 0
85
+ end
86
+ it "should reject a unit of work when worker fails" do
87
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
88
+ with_test_queuefactory(ctx,false)
89
+
90
+ any_instance_of(DummyWorker){ |w| mock(w).work(anything){ false } }
91
+ mock(DummyWorker).error(anything, anything){ |text, _| text.must_match(/^REJECTED/) }
92
+ DummyWorker.start(ctx)
93
+ DummyWorker.jobs_stats[:failed].must_equal 1
94
+ DummyWorker.jobs_stats[:passed].must_equal 0
95
+ end
96
+ it "should reject a unit of work when worker times out" do
97
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
98
+ with_test_queuefactory(ctx,false)
99
+ DummyWorker.queue_opts[:timeout_job_after] = 1
100
+ any_instance_of(DummyWorker){ |w| mock(w).work(anything){ sleep(2) }}
101
+ mock(DummyWorker).error(anything, anything){ |text, _| text.must_match(/^TIMEOUT/) }
102
+ DummyWorker.start(ctx)
103
+ DummyWorker.jobs_stats[:failed].must_equal 1
104
+ DummyWorker.jobs_stats[:passed].must_equal 0
105
+ DummyWorker.queue_opts[:timeout_job_after] = 5
106
+ end
107
+ it "should reject a unit of work when worker fails exceptionally" do
108
+ ctx = FrenzyBunnies::Context.new(:logger=> Logger.new(nil))
109
+ with_test_queuefactory(ctx,false)
110
+
111
+ any_instance_of(DummyWorker){ |w| mock(w).work(anything){ throw :error } }
112
+ mock(DummyWorker).error(anything, anything){ |text, _| text.must_match(/^ERROR/) }
113
+ DummyWorker.start(ctx)
114
+ DummyWorker.jobs_stats[:failed].must_equal 1
115
+ DummyWorker.jobs_stats[:passed].must_equal 0
116
+ end
117
+ end
@@ -0,0 +1,35 @@
1
+ #require 'simplecov'
2
+ #SimpleCov.start if ENV["COVERAGE"]
3
+
4
+ require 'minitest/autorun'
5
+
6
+
7
+
8
+ require 'rr'
9
+
10
+
11
+ class MiniTest::Unit::TestCase
12
+ include RR::Adapters::MiniTest
13
+ end
14
+
15
+
16
+ require 'thor'
17
+ # This is to silence the 'task' warning for the mocks.
18
+ #
19
+ class Thor
20
+ class << self
21
+ def create_task(meth) #:nodoc:
22
+ if @usage && @desc
23
+ base_class = @hide ? Thor::HiddenTask : Thor::Task
24
+ tasks[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
25
+ @usage, @desc, @long_desc, @method_options, @hide = nil
26
+ true
27
+ elsif self.all_tasks[meth] || meth == "method_missing"
28
+ true
29
+ else
30
+ false
31
+ end
32
+ end
33
+ end
34
+ end
35
+
metadata ADDED
@@ -0,0 +1,184 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: boardintel_frenzy_bunnies
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.17
5
+ platform: java
6
+ authors:
7
+ - Dotan Nahum
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '='
17
+ - !ruby/object:Gem::Version
18
+ version: 3.0.0
19
+ name: march_hare
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - '='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.4.8
33
+ name: sinatra
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.4.8
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.99
47
+ name: atomic
48
+ prerelease: false
49
+ type: :runtime
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.1.99
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '='
59
+ - !ruby/object:Gem::Version
60
+ version: 1.8.6
61
+ name: json
62
+ prerelease: false
63
+ type: :runtime
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.8.6
69
+ - !ruby/object:Gem::Dependency
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ name: guard-coffeescript
76
+ prerelease: false
77
+ type: :development
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ name: rr
90
+ prerelease: false
91
+ type: :development
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ name: guard-minitest
104
+ prerelease: false
105
+ type: :development
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: RabbitMQ JRuby based workers on top of march_hare
112
+ email:
113
+ - jondotan@gmail.com
114
+ executables:
115
+ - frenzy_bunnies
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".ruby-version"
121
+ - Gemfile
122
+ - Guardfile
123
+ - LICENSE
124
+ - README.md
125
+ - Rakefile
126
+ - bin/frenzy_bunnies
127
+ - examples/feed.rb
128
+ - examples/feed_worker.rb
129
+ - examples/feed_workers_bin.rb
130
+ - fb-cap.png
131
+ - frenzy_bunnies.gemspec
132
+ - lib/frenzy_bunnies.rb
133
+ - lib/frenzy_bunnies/cli.rb
134
+ - lib/frenzy_bunnies/context.rb
135
+ - lib/frenzy_bunnies/handlers/maxretry.rb
136
+ - lib/frenzy_bunnies/handlers/oneshot.rb
137
+ - lib/frenzy_bunnies/health.rb
138
+ - lib/frenzy_bunnies/health/collector.rb
139
+ - lib/frenzy_bunnies/health/providers/jvm.rb
140
+ - lib/frenzy_bunnies/queue_factory.rb
141
+ - lib/frenzy_bunnies/version.rb
142
+ - lib/frenzy_bunnies/web.rb
143
+ - lib/frenzy_bunnies/web/public/css/bootstrap.min.css
144
+ - lib/frenzy_bunnies/web/public/img/bunny16.png
145
+ - lib/frenzy_bunnies/web/public/img/bunny32.png
146
+ - lib/frenzy_bunnies/web/public/index.html
147
+ - lib/frenzy_bunnies/web/public/js/app.coffee
148
+ - lib/frenzy_bunnies/web/public/js/app.js
149
+ - lib/frenzy_bunnies/web/public/js/backbone-min.js
150
+ - lib/frenzy_bunnies/web/public/js/bootstrap.js
151
+ - lib/frenzy_bunnies/web/public/js/bootstrap.min.js
152
+ - lib/frenzy_bunnies/web/public/js/jquery-1.8.0.min.js
153
+ - lib/frenzy_bunnies/web/public/js/jquery.filesize.js
154
+ - lib/frenzy_bunnies/web/public/js/jquery.timeago.js
155
+ - lib/frenzy_bunnies/web/public/js/underscore-min.js
156
+ - lib/frenzy_bunnies/worker.rb
157
+ - spec/frenzy_bunnies/worker_spec.rb
158
+ - spec/spec_helper.rb
159
+ homepage: ''
160
+ licenses: []
161
+ metadata: {}
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '0'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubyforge_project:
178
+ rubygems_version: 2.6.14
179
+ signing_key:
180
+ specification_version: 4
181
+ summary: RabbitMQ JRuby based workers on top of march_hare
182
+ test_files:
183
+ - spec/frenzy_bunnies/worker_spec.rb
184
+ - spec/spec_helper.rb