sneakers 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitignore +6 -17
  2. data/Gemfile +0 -1
  3. data/Gemfile.lock +152 -0
  4. data/Guardfile +8 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +140 -9
  7. data/Rakefile +9 -0
  8. data/bin/sneakers +5 -0
  9. data/examples/benchmark_worker.rb +21 -0
  10. data/examples/metrics_worker.rb +28 -0
  11. data/examples/profiling_worker.rb +55 -0
  12. data/examples/sneakers.conf.rb.example +10 -0
  13. data/examples/title_scraper.rb +20 -0
  14. data/examples/workflow_worker.rb +24 -0
  15. data/lib/sneakers.rb +80 -1
  16. data/lib/sneakers/cli.rb +107 -0
  17. data/lib/sneakers/concerns/logging.rb +34 -0
  18. data/lib/sneakers/concerns/metrics.rb +34 -0
  19. data/lib/sneakers/handlers/oneshot.rb +25 -0
  20. data/lib/sneakers/metrics/logging_metrics.rb +16 -0
  21. data/lib/sneakers/metrics/null_metrics.rb +13 -0
  22. data/lib/sneakers/metrics/statsd_metrics.rb +21 -0
  23. data/lib/sneakers/publisher.rb +35 -0
  24. data/lib/sneakers/queue.rb +42 -0
  25. data/lib/sneakers/runner.rb +20 -0
  26. data/lib/sneakers/runner_config.rb +55 -0
  27. data/lib/sneakers/support/production_formatter.rb +11 -0
  28. data/lib/sneakers/support/queue_name.rb +14 -0
  29. data/lib/sneakers/support/utils.rb +18 -0
  30. data/lib/sneakers/tasks.rb +34 -0
  31. data/lib/sneakers/version.rb +1 -1
  32. data/lib/sneakers/worker.rb +120 -0
  33. data/lib/sneakers/workergroup.rb +47 -0
  34. data/sneakers.gemspec +26 -16
  35. data/spec/fixtures/require_worker.rb +17 -0
  36. data/spec/sneakers/cli_spec.rb +53 -0
  37. data/spec/sneakers/concerns/logging.rb +39 -0
  38. data/spec/sneakers/concerns/metrics.rb +38 -0
  39. data/spec/sneakers/publisher_spec.rb +37 -0
  40. data/spec/sneakers/queue_spec.rb +42 -0
  41. data/spec/sneakers/worker_spec.rb +348 -0
  42. data/spec/spec_helper.rb +10 -0
  43. metadata +216 -14
data/.gitignore CHANGED
@@ -1,17 +1,6 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ sneakers.yaml
2
+ sneakers.log
3
+ sneakers.pid
4
+ pkg/
5
+ coverage/
6
+ tmp/
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in sneakers.gemspec
4
3
  gemspec
@@ -0,0 +1,152 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sneakers (0.0.2)
5
+ bunny (>= 0.9.0.rc2)
6
+ serverengine
7
+ thor
8
+ thread
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (3.2.14)
14
+ i18n (~> 0.6, >= 0.6.4)
15
+ multi_json (~> 1.0)
16
+ amq-protocol (1.7.0)
17
+ arrayfields (4.9.0)
18
+ awesome_print (1.1.0)
19
+ bluff (0.1.0)
20
+ bunny (1.0.0.pre6)
21
+ amq-protocol (>= 1.7.0)
22
+ cane (2.6.0)
23
+ parallel
24
+ chronic (0.10.2)
25
+ churn (0.0.33)
26
+ chronic (>= 0.2.3)
27
+ hirb
28
+ json_pure
29
+ main
30
+ ruby_parser (~> 3.0)
31
+ sexp_processor (~> 4.1)
32
+ code_analyzer (0.4.2)
33
+ sexp_processor
34
+ code_metrics (0.1.0)
35
+ coderay (1.0.9)
36
+ colored (1.2)
37
+ erubis (2.7.0)
38
+ fattr (2.2.1)
39
+ ffi (1.9.0)
40
+ flay (2.4.0)
41
+ ruby_parser (~> 3.0)
42
+ sexp_processor (~> 4.0)
43
+ flog (4.1.2)
44
+ ruby_parser (~> 3.1, > 3.1.0)
45
+ sexp_processor (~> 4.0)
46
+ formatador (0.2.4)
47
+ guard (1.8.2)
48
+ formatador (>= 0.2.4)
49
+ listen (>= 1.0.0)
50
+ lumberjack (>= 1.0.2)
51
+ pry (>= 0.9.10)
52
+ thor (>= 0.14.6)
53
+ guard-minitest (1.3.0)
54
+ guard (>= 1.8)
55
+ minitest (>= 2.1)
56
+ hirb (0.7.1)
57
+ i18n (0.6.5)
58
+ json_pure (1.8.0)
59
+ listen (1.3.1)
60
+ rb-fsevent (>= 0.9.3)
61
+ rb-inotify (>= 0.9)
62
+ rb-kqueue (>= 0.2)
63
+ lumberjack (1.0.4)
64
+ main (5.2.0)
65
+ arrayfields (>= 4.7.4)
66
+ chronic (>= 0.6.2)
67
+ fattr (>= 2.2.0)
68
+ map (>= 5.1.0)
69
+ map (6.5.1)
70
+ method_source (0.8.2)
71
+ metric_fu (4.4.1)
72
+ bluff
73
+ cane (~> 2.5, >= 2.5.2)
74
+ churn (~> 0.0.28)
75
+ code_metrics (~> 0.1)
76
+ coderay
77
+ flay (~> 2.1, >= 2.0.1)
78
+ flog (~> 4.1, >= 4.1.1)
79
+ metric_fu-Saikuro (>= 1.1.1.0)
80
+ multi_json
81
+ rails_best_practices (~> 1.14, >= 1.14.3)
82
+ redcard
83
+ reek (~> 1.3, >= 1.3.3)
84
+ roodi (~> 3.1)
85
+ metric_fu-Saikuro (1.1.1.0)
86
+ mini_portile (0.5.1)
87
+ minitest (5.0.7)
88
+ multi_json (1.8.0)
89
+ nokogiri (1.6.0)
90
+ mini_portile (~> 0.5.0)
91
+ parallel (0.8.3)
92
+ pry (0.9.12.2)
93
+ coderay (~> 1.0.5)
94
+ method_source (~> 0.8)
95
+ slop (~> 3.4)
96
+ rails_best_practices (1.14.3)
97
+ activesupport
98
+ awesome_print
99
+ code_analyzer (>= 0.4.2)
100
+ colored
101
+ erubis
102
+ i18n
103
+ require_all
104
+ ruby-progressbar
105
+ rake (10.1.0)
106
+ rb-fsevent (0.9.3)
107
+ rb-inotify (0.9.2)
108
+ ffi (>= 0.5.0)
109
+ rb-kqueue (0.2.0)
110
+ ffi (>= 0.5.0)
111
+ redcard (1.1.0)
112
+ reek (1.3.3)
113
+ ruby2ruby (~> 2.0.2)
114
+ ruby_parser (~> 3.1, >= 3.1.1)
115
+ sexp_processor
116
+ require_all (1.3.1)
117
+ roodi (3.1.1)
118
+ ruby_parser (~> 3.2, >= 3.2.2)
119
+ rr (1.1.1)
120
+ ruby-prof (0.13.0)
121
+ ruby-progressbar (1.2.0)
122
+ ruby2ruby (2.0.6)
123
+ ruby_parser (~> 3.1)
124
+ sexp_processor (~> 4.0)
125
+ ruby_parser (3.2.2)
126
+ sexp_processor (~> 4.1)
127
+ serverengine (1.5.4)
128
+ sigdump (~> 0.2.2)
129
+ sexp_processor (4.3.0)
130
+ sigdump (0.2.2)
131
+ simplecov (0.7.1)
132
+ multi_json (~> 1.0)
133
+ simplecov-html (~> 0.7.1)
134
+ simplecov-html (0.7.1)
135
+ simplecov-rcov-text (0.0.2)
136
+ slop (3.4.6)
137
+ thor (0.18.1)
138
+ thread (0.1.1)
139
+
140
+ PLATFORMS
141
+ ruby
142
+
143
+ DEPENDENCIES
144
+ guard-minitest
145
+ metric_fu
146
+ nokogiri
147
+ rake
148
+ rr
149
+ ruby-prof
150
+ simplecov
151
+ simplecov-rcov-text
152
+ sneakers!
@@ -0,0 +1,8 @@
1
+
2
+ guard :minitest do
3
+ watch(%r{^spec/(.*)_spec\.rb})
4
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
5
+ watch(%r{^spec/spec_helper\.rb}) { 'spec' }
6
+ end
7
+
8
+
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 jondot
1
+ Copyright (c) 2013 Dotan Nahum
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,20 @@
1
1
  # Sneakers
2
2
 
3
- TODO: Write a gem description
3
+
4
+ ```
5
+ __
6
+ ,--' >
7
+ `=====
8
+
9
+ ```
10
+
11
+
12
+ A high-performance RabbitMQ background processing framework for
13
+ Ruby.
14
+
15
+ Visit the [[wiki]]](https://github.com/jondot/sneakers/wiki) for
16
+ complete docs.
17
+
4
18
 
5
19
  ## Installation
6
20
 
@@ -16,14 +30,131 @@ Or install it yourself as:
16
30
 
17
31
  $ gem install sneakers
18
32
 
19
- ## Usage
20
33
 
21
- TODO: Write usage instructions here
34
+ ## Quick start
35
+
36
+ Set up a Gemfile
37
+
38
+ ```ruby
39
+ source 'https://rubygems.org'
40
+ gem 'sneakers'
41
+ gem 'json'
42
+ gem 'redis'
43
+ ```
44
+
45
+ And a worker
46
+
47
+ ```ruby
48
+ require 'sneakers'
49
+ require 'redis'
50
+ require 'json'
51
+
52
+ $redis = Redis.new
53
+
54
+ class Processor
55
+ include Sneakers::Worker
56
+ from_queue :logs
57
+
58
+
59
+ def work(msg)
60
+ err = JSON.parse(msg)
61
+ if err["type"] == "error"
62
+ $redis.incr "processor:#{err["error"]}"
63
+ end
64
+
65
+ ack!
66
+ end
67
+ end
68
+ ```
69
+
70
+
71
+ As an example, make a message look like this:
72
+ We'll count errors and error types with Redis. Specifically for an error that looks like this:
73
+
74
+ ```javascript
75
+ {
76
+ "type": "error",
77
+ "message": "HALP!",
78
+ "error": "CODE001"
79
+ }
80
+ ```
81
+
82
+
83
+ Let's test it out quickly from the command line:
84
+
85
+
86
+ ```bash
87
+ sneakers work Processor --require boot.rb --front
88
+ ```
89
+
90
+ We just told Sneakers to spawn a worker named `Processor`, but first `--require` a file that we dedicate to setting up environment, including workers and what-not.
91
+
92
+ For simplicity, we also told Sneakers to *not* daemonize and work at the `--front`.
93
+
94
+ If you go to your RabbitMQ admin now, you'll see a new queue named `logs` was created. Push a couple messages, and this is the output you should see at your terminal.
95
+
96
+
97
+ ```
98
+ 2013-10-11T19:26:36Z p-4718 t-ovqgyb31o DEBUG: [worker-logs:1:213mmy][#<Thread:0x007fae6b05cc58>][logs][{:prefetch=>10, :durable=>true, :ack=>true, :heartbeat_interval=>2, :exchange=>"sneakers"}] Working off: log log
99
+ 2013-10-11T19:26:36Z p-4718 t-ovqgyrxu4 INFO: log log
100
+ 2013-10-11T19:26:40Z p-4719 t-ovqgyb364 DEBUG: [worker-logs:1:h23iit][#<Thread:0x007fae6b05cd98>][logs][{:prefetch=>10, :durable=>true, :ack=>true, :heartbeat_interval=>2, :exchange=>"sneakers"}] Working off: log log
101
+ 2013-10-11T19:26:40Z p-4719 t-ovqgyrx8g INFO: log log
102
+ ```
103
+
104
+ And redis will show this:
105
+
106
+
107
+ ```
108
+ ➜ ~ redis-cli monitor
109
+ 1381520329.888581 [0 127.0.0.1:49182] "incr" "processor:CODE001"
110
+ ```
111
+
112
+
113
+ We're basically done with the ceremonies and all is left is to do some real work.
114
+
115
+
116
+
117
+ ### Looking at metrics
118
+
119
+ Let's use the `logging_metrics` provider just for the sake of fun of seeing the metrics as they happen.
120
+
121
+ ```ruby
122
+ # boot.rb
123
+ require 'sneakers'
124
+ require 'redis'
125
+ require 'json'
126
+ require 'sneakers/metrics/logging_metrics'
127
+ Sneakers.configure :metrics => Sneakers::Metrics::LoggingMetrics.new
128
+
129
+ # ... rest of code
130
+ ```
131
+
132
+ Now push a message again and you'll see:
133
+
134
+ ```
135
+ 2013-10-11T19:44:37Z p-9219 t-oxh8owywg INFO: INC: work.Processor.started
136
+ 2013-10-11T19:44:37Z p-9219 t-oxh8owywg INFO: TIME: work.Processor.time 0.00242
137
+ 2013-10-11T19:44:37Z p-9219 t-oxh8owywg INFO: INC: work.Processor.handled.ack
138
+ ```
139
+
140
+ Which increments start + end, and times the work unit.
141
+
142
+
143
+
144
+ From here, you can continue over to the
145
+ [[Wiki]](https://github.com/jondot/sneakers/wiki)
146
+
147
+ # Contributing
148
+
149
+ Fork, implement, add tests, pull request, get my everlasting thanks and a respectable place here :).
150
+
151
+ # Copyright
152
+
153
+ Copyright (c) 2013 [Dotan Nahum](http://gplus.to/dotan) [@jondot](http://twitter.com/jondot). See MIT-LICENSE for further details.
154
+
155
+
156
+
157
+
158
+
22
159
 
23
- ## Contributing
24
160
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
data/Rakefile CHANGED
@@ -1 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'metric_fu'
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "spec"
7
+ t.test_files = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'sneakers'
3
+ require 'sneakers/cli'
4
+
5
+ Sneakers::CLI.start
@@ -0,0 +1,21 @@
1
+ $: << File.expand_path('../lib', File.dirname(__FILE__))
2
+ require 'sneakers'
3
+
4
+ class BenchmarkWorker
5
+ include Sneakers::Worker
6
+ from_queue 'downloads',
7
+ :env => 'test',
8
+ :durable => false,
9
+ :ack => true,
10
+ :threads => 50,
11
+ :prefetch => 50,
12
+ :timeout_job_after => 1,
13
+ :exchange => 'dummy',
14
+ :heartbeat_interval => 5
15
+ def work(msg)
16
+ ack!
17
+ end
18
+ end
19
+
20
+
21
+
@@ -0,0 +1,28 @@
1
+ $: << File.expand_path('../lib', File.dirname(__FILE__))
2
+ require 'sneakers'
3
+ require 'sneakers/runner'
4
+ require 'sneakers/metrics/logging_metrics'
5
+ require 'open-uri'
6
+ require 'nokogiri'
7
+
8
+
9
+ class MetricsWorker
10
+ include Sneakers::Worker
11
+
12
+ from_queue 'downloads'
13
+
14
+ def work(msg)
15
+ doc = Nokogiri::HTML(open(msg))
16
+ logger.info "FOUND <#{doc.css('title').text}>"
17
+ ack!
18
+ end
19
+ end
20
+
21
+
22
+ Sneakers.configure( :daemonize => false, :log => STDOUT, :metrics => Sneakers::Metrics::LoggingMetrics.new)
23
+ r = Sneakers::Runner.new([ MetricsWorker ])
24
+ r.run
25
+
26
+
27
+
28
+
@@ -0,0 +1,55 @@
1
+ $: << File.expand_path('../lib', File.dirname(__FILE__))
2
+ require 'sneakers'
3
+ require 'sneakers/runner'
4
+ require 'ruby-prof'
5
+
6
+
7
+ puts "feeding messages in"
8
+ 1000.times {
9
+ Sneakers.publish("{}", :to_queue => 'downloads')
10
+ puts "done"
11
+
12
+
13
+ class ProfilingWorker
14
+ include Sneakers::Worker
15
+ from_queue 'downloads',
16
+ :env => '',
17
+ :durable => false,
18
+ :ack => true,
19
+ :threads => 50,
20
+ :prefetch => 50,
21
+ :timeout_job_after => 1,
22
+ :exchange => 'dummy',
23
+ :heartbeat_interval => 5
24
+ def work(msg)
25
+ ack!
26
+ end
27
+ end
28
+
29
+
30
+
31
+ r = Sneakers::Runner.new
32
+ Sneakers::Worker.configure_logger(Logger.new('/dev/null'))
33
+
34
+ # ctrl-c and Ruby 2.0 breaks signal handling
35
+ # Sidekiq has same issues
36
+ # https://github.com/mperham/sidekiq/issues/728
37
+ #
38
+ # so we use a timeout and a thread that kills profiling
39
+ puts "profiling start"
40
+ RubyProf.start
41
+
42
+ Thread.new do
43
+ sleep 10
44
+ puts "stopping profiler"
45
+ result = RubyProf.stop
46
+
47
+ # Print a flat profile to text
48
+ printer = RubyProf::FlatPrinter.new(result)
49
+ printer.print(STDOUT)
50
+ r.stop
51
+ exit(0)
52
+ end
53
+
54
+ r.run([ ProfilingWorker ])
55
+