sneakers 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -17
- data/Gemfile +0 -1
- data/Gemfile.lock +152 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +2 -2
- data/README.md +140 -9
- data/Rakefile +9 -0
- data/bin/sneakers +5 -0
- data/examples/benchmark_worker.rb +21 -0
- data/examples/metrics_worker.rb +28 -0
- data/examples/profiling_worker.rb +55 -0
- data/examples/sneakers.conf.rb.example +10 -0
- data/examples/title_scraper.rb +20 -0
- data/examples/workflow_worker.rb +24 -0
- data/lib/sneakers.rb +80 -1
- data/lib/sneakers/cli.rb +107 -0
- data/lib/sneakers/concerns/logging.rb +34 -0
- data/lib/sneakers/concerns/metrics.rb +34 -0
- data/lib/sneakers/handlers/oneshot.rb +25 -0
- data/lib/sneakers/metrics/logging_metrics.rb +16 -0
- data/lib/sneakers/metrics/null_metrics.rb +13 -0
- data/lib/sneakers/metrics/statsd_metrics.rb +21 -0
- data/lib/sneakers/publisher.rb +35 -0
- data/lib/sneakers/queue.rb +42 -0
- data/lib/sneakers/runner.rb +20 -0
- data/lib/sneakers/runner_config.rb +55 -0
- data/lib/sneakers/support/production_formatter.rb +11 -0
- data/lib/sneakers/support/queue_name.rb +14 -0
- data/lib/sneakers/support/utils.rb +18 -0
- data/lib/sneakers/tasks.rb +34 -0
- data/lib/sneakers/version.rb +1 -1
- data/lib/sneakers/worker.rb +120 -0
- data/lib/sneakers/workergroup.rb +47 -0
- data/sneakers.gemspec +26 -16
- data/spec/fixtures/require_worker.rb +17 -0
- data/spec/sneakers/cli_spec.rb +53 -0
- data/spec/sneakers/concerns/logging.rb +39 -0
- data/spec/sneakers/concerns/metrics.rb +38 -0
- data/spec/sneakers/publisher_spec.rb +37 -0
- data/spec/sneakers/queue_spec.rb +42 -0
- data/spec/sneakers/worker_spec.rb +348 -0
- data/spec/spec_helper.rb +10 -0
- metadata +216 -14
data/.gitignore
CHANGED
@@ -1,17 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
.
|
4
|
-
|
5
|
-
|
6
|
-
|
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
data/Gemfile.lock
ADDED
@@ -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!
|
data/Guardfile
ADDED
data/LICENSE.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2013
|
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
|
-
|
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
|
-
|
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
data/bin/sneakers
ADDED
@@ -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
|
+
|