sneakers 0.0.7 → 0.1.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +20 -0
- data/Gemfile.lock +7 -7
- data/README.md +15 -0
- data/ROADMAP.md +18 -0
- data/lib/sneakers.rb +4 -0
- data/lib/sneakers/cli.rb +4 -0
- data/lib/sneakers/metrics/newrelic_metrics.rb +37 -0
- data/lib/sneakers/queue.rb +7 -1
- data/lib/sneakers/version.rb +1 -1
- data/lib/sneakers/worker.rb +7 -2
- data/sneakers.gemspec +1 -1
- data/spec/sneakers/queue_spec.rb +36 -18
- data/spec/sneakers/sneakers_spec.rb +20 -0
- data/spec/sneakers/worker_spec.rb +36 -2
- metadata +12 -9
data/CHANGELOG.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# 0.1.0, Not released yet
|
2
|
+
|
3
|
+
+ Added newrelic stats reporter (@arielze)
|
4
|
+
+ Added explicit routing_key at queue (@arielze)
|
5
|
+
+ Depracating self-daemonization (@jondot)
|
6
|
+
+ updating bunny (@michaelklishin)
|
7
|
+
+ Fix reference in publisher (@sergei-matheson)
|
8
|
+
+ Allow binding of multiple routing keys (@SebastianEdwards)
|
9
|
+
+ added work_with_params for advanced handling of work items with amqp
|
10
|
+
headers. (#12)
|
11
|
+
+ Bunny.not_environmental! will no disable auto-environment discovery.
|
12
|
+
(#15)
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
# 0.0.7
|
18
|
+
|
19
|
+
+ Sneakers core.
|
20
|
+
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sneakers (0.0
|
5
|
-
bunny (
|
4
|
+
sneakers (0.1.0)
|
5
|
+
bunny (~> 1.0.7)
|
6
6
|
serverengine
|
7
7
|
thor
|
8
8
|
thread
|
@@ -13,12 +13,12 @@ GEM
|
|
13
13
|
activesupport (3.2.15)
|
14
14
|
i18n (~> 0.6, >= 0.6.4)
|
15
15
|
multi_json (~> 1.0)
|
16
|
-
amq-protocol (1.
|
16
|
+
amq-protocol (1.9.2)
|
17
17
|
arrayfields (4.9.0)
|
18
18
|
awesome_print (1.2.0)
|
19
19
|
bluff (0.1.0)
|
20
|
-
bunny (0.
|
21
|
-
amq-protocol (>= 1.
|
20
|
+
bunny (1.0.7)
|
21
|
+
amq-protocol (>= 1.9.2)
|
22
22
|
cane (2.6.0)
|
23
23
|
parallel
|
24
24
|
celluloid (0.15.2)
|
@@ -124,7 +124,7 @@ GEM
|
|
124
124
|
sexp_processor (~> 4.0)
|
125
125
|
ruby_parser (3.2.2)
|
126
126
|
sexp_processor (~> 4.1)
|
127
|
-
serverengine (1.5.
|
127
|
+
serverengine (1.5.7)
|
128
128
|
sigdump (~> 0.2.2)
|
129
129
|
sexp_processor (4.3.0)
|
130
130
|
sigdump (0.2.2)
|
@@ -135,7 +135,7 @@ GEM
|
|
135
135
|
simplecov-rcov-text (0.0.2)
|
136
136
|
slop (3.4.6)
|
137
137
|
thor (0.18.1)
|
138
|
-
thread (0.1.
|
138
|
+
thread (0.1.3)
|
139
139
|
timers (1.1.0)
|
140
140
|
|
141
141
|
PLATFORMS
|
data/README.md
CHANGED
@@ -12,6 +12,10 @@
|
|
12
12
|
A high-performance RabbitMQ background processing framework for
|
13
13
|
Ruby.
|
14
14
|
|
15
|
+
|
16
|
+
Sneakers is being used in production for both I/O and CPU intensive workloads, and have achieved the goals of high-performance and 0-maintenance, as designed.
|
17
|
+
|
18
|
+
|
15
19
|
Visit the [wiki](https://github.com/jondot/sneakers/wiki) for
|
16
20
|
complete docs.
|
17
21
|
|
@@ -146,6 +150,17 @@ From here, you can continue over to the
|
|
146
150
|
|
147
151
|
Fork, implement, add tests, pull request, get my everlasting thanks and a respectable place here :).
|
148
152
|
|
153
|
+
|
154
|
+
### Thanks:
|
155
|
+
|
156
|
+
* Michael Klishin - @michaelklishin
|
157
|
+
* Ariel Zerahia - @arielze
|
158
|
+
* @sergei-matheson
|
159
|
+
* Sebastian Edwards - @SebastianEdwards
|
160
|
+
* Tor Ivry - @torkale
|
161
|
+
|
162
|
+
|
163
|
+
|
149
164
|
# Copyright
|
150
165
|
|
151
166
|
Copyright (c) 2013 [Dotan Nahum](http://gplus.to/dotan) [@jondot](http://twitter.com/jondot). See MIT-LICENSE for further details.
|
data/ROADMAP.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# Roadmap
|
2
|
+
|
3
|
+
It is essential to keep a clear roadmap.
|
4
|
+
In its core, Sneakers is already production-ready. However, it is vital
|
5
|
+
to take in feedback and improve what can be improved :)
|
6
|
+
|
7
|
+
This document will communicate the stages that the next version is at.
|
8
|
+
See `CHANGELOG.md` for new features that are in.
|
9
|
+
|
10
|
+
|
11
|
+
# v0.1.0 (next version)
|
12
|
+
|
13
|
+
- Taking in community pull requests and feedback
|
14
|
+
- Verify production readiness and performance
|
15
|
+
- Full performance test suite
|
16
|
+
|
17
|
+
|
18
|
+
|
data/lib/sneakers.rb
CHANGED
data/lib/sneakers/cli.rb
CHANGED
@@ -35,6 +35,10 @@ module Sneakers
|
|
35
35
|
|
36
36
|
opts[:log] = opts[:daemonize] ? 'sneakers.log' : STDOUT
|
37
37
|
|
38
|
+
if opts[:daemonize]
|
39
|
+
puts "*** DEPRACATED: self-daemonization '--daemonize' is considered a bad practice, which is why this feature will be removed in future versions. Please run Sneakers in front, and use things like upstart, systemd, or supervisor to manage it as a daemon."
|
40
|
+
end
|
41
|
+
|
38
42
|
|
39
43
|
Sneakers.configure(opts)
|
40
44
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Sneakers
|
2
|
+
module Metrics
|
3
|
+
class NewrelicMetrics
|
4
|
+
|
5
|
+
def self.eagent(eagent = nil)
|
6
|
+
@eagent = eagent || @eagent
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize()
|
10
|
+
#@connection = conn
|
11
|
+
end
|
12
|
+
|
13
|
+
def increment(metric)
|
14
|
+
record_stat metric, 1
|
15
|
+
end
|
16
|
+
|
17
|
+
def record_stat(metric, num)
|
18
|
+
stats(metric).record_data_point(num)
|
19
|
+
rescue Exception => e
|
20
|
+
puts "NewrelicMetrics#record_stat: #{e}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def timing(metric, &block)
|
24
|
+
start = Time.now
|
25
|
+
block.call
|
26
|
+
record_stat(metric, ((Time.now - start)*1000).floor)
|
27
|
+
end
|
28
|
+
|
29
|
+
def stats(metric)
|
30
|
+
metric.gsub! "\.", "\/"
|
31
|
+
NewrelicMetrics.eagent::Agent.get_stats("Custom/#{metric}")
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
data/lib/sneakers/queue.rb
CHANGED
@@ -28,8 +28,14 @@ class Sneakers::Queue
|
|
28
28
|
|
29
29
|
handler = @handler_klass.new(@channel)
|
30
30
|
|
31
|
+
routing_key = @opts[:routing_key] || @name
|
32
|
+
routing_keys = [*routing_key]
|
33
|
+
|
31
34
|
queue = @channel.queue(@name, :durable => @opts[:durable])
|
32
|
-
|
35
|
+
|
36
|
+
routing_keys.each do |key|
|
37
|
+
queue.bind(@exchange, :routing_key => key)
|
38
|
+
end
|
33
39
|
|
34
40
|
@consumer = queue.subscribe(:block => false, :ack => @opts[:ack]) do | hdr, props, msg |
|
35
41
|
worker.do_work(hdr, props, msg, handler)
|
data/lib/sneakers/version.rb
CHANGED
data/lib/sneakers/worker.rb
CHANGED
@@ -23,6 +23,7 @@ module Sneakers
|
|
23
23
|
@should_ack = opts[:ack]
|
24
24
|
@timeout_after = opts[:timeout_job_after]
|
25
25
|
@pool = pool || Thread.pool(opts[:threads]) # XXX config threads
|
26
|
+
@call_with_params = respond_to?(:work_with_params)
|
26
27
|
|
27
28
|
@queue = queue || Sneakers::Queue.new(
|
28
29
|
queue_name,
|
@@ -39,7 +40,7 @@ module Sneakers
|
|
39
40
|
|
40
41
|
def publish(msg, routing)
|
41
42
|
return unless routing[:to_queue]
|
42
|
-
@queue.exchange.publish(msg, :routing_key => QueueName.new(routing[:to_queue], @opts).to_s)
|
43
|
+
@queue.exchange.publish(msg, :routing_key => Support::QueueName.new(routing[:to_queue], @opts).to_s)
|
43
44
|
end
|
44
45
|
|
45
46
|
def do_work(hdr, props, msg, handler)
|
@@ -53,7 +54,11 @@ module Sneakers
|
|
53
54
|
metrics.increment("work.#{self.class.name}.started")
|
54
55
|
Timeout.timeout(@timeout_after) do
|
55
56
|
metrics.timing("work.#{self.class.name}.time") do
|
56
|
-
|
57
|
+
if @call_with_params
|
58
|
+
res = work_with_params(msg, hdr, props)
|
59
|
+
else
|
60
|
+
res = work(msg)
|
61
|
+
end
|
57
62
|
end
|
58
63
|
end
|
59
64
|
rescue Timeout::Error
|
data/sneakers.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
gem.add_dependency "serverengine"
|
20
|
-
gem.add_dependency "bunny", "
|
20
|
+
gem.add_dependency "bunny", "~> 1.0.7"
|
21
21
|
gem.add_dependency "thread"
|
22
22
|
gem.add_dependency "thor"
|
23
23
|
|
data/spec/sneakers/queue_spec.rb
CHANGED
@@ -9,8 +9,8 @@ describe Sneakers::Queue do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "#subscribe" do
|
12
|
-
|
13
|
-
|
12
|
+
let :queue_vars do
|
13
|
+
{
|
14
14
|
:prefetch => 25,
|
15
15
|
:durable => true,
|
16
16
|
:ack => true,
|
@@ -18,22 +18,40 @@ describe Sneakers::Queue do
|
|
18
18
|
:vhost => '/',
|
19
19
|
:exchange => "sneakers",
|
20
20
|
:exchange_type => :direct
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
mock(
|
32
|
-
mock(
|
33
|
-
|
34
|
-
|
35
|
-
mock(
|
36
|
-
mock(
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
before do
|
25
|
+
@mkbunny = Object.new
|
26
|
+
@mkchan = Object.new
|
27
|
+
@mkex = Object.new
|
28
|
+
@mkqueue = Object.new
|
29
|
+
|
30
|
+
mock(@mkbunny).start {}
|
31
|
+
mock(@mkbunny).create_channel{ @mkchan }
|
32
|
+
mock(Bunny).new(anything, :vhost => '/', :heartbeat => 2){ @mkbunny }
|
33
|
+
|
34
|
+
mock(@mkchan).prefetch(25)
|
35
|
+
mock(@mkchan).exchange("sneakers", :type => :direct, :durable => true){ @mkex }
|
36
|
+
mock(@mkchan).queue("downloads", :durable => true){ @mkqueue }
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should setup a bunny queue according to configuration values" do
|
40
|
+
q = Sneakers::Queue.new("downloads", queue_vars)
|
41
|
+
|
42
|
+
mock(@mkqueue).bind(@mkex, :routing_key => "downloads")
|
43
|
+
mock(@mkqueue).subscribe(:block => false, :ack => true)
|
44
|
+
|
45
|
+
q.subscribe(Object.new)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "supports multiple routing_keys" do
|
49
|
+
q = Sneakers::Queue.new("downloads",
|
50
|
+
queue_vars.merge(:routing_key => ["alpha", "beta"]))
|
51
|
+
|
52
|
+
mock(@mkqueue).bind(@mkex, :routing_key => "alpha")
|
53
|
+
mock(@mkqueue).bind(@mkex, :routing_key => "beta")
|
54
|
+
mock(@mkqueue).subscribe(:block => false, :ack => true)
|
37
55
|
|
38
56
|
q.subscribe(Object.new)
|
39
57
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'sneakers'
|
3
3
|
|
4
|
+
class EnvWorker
|
5
|
+
include Sneakers::Worker
|
6
|
+
from_queue 'defaults'
|
7
|
+
|
8
|
+
def work(msg)
|
9
|
+
end
|
10
|
+
end
|
4
11
|
|
5
12
|
|
6
13
|
describe Sneakers do
|
@@ -33,6 +40,19 @@ describe Sneakers do
|
|
33
40
|
end
|
34
41
|
end
|
35
42
|
|
43
|
+
describe '.not_environmental!' do
|
44
|
+
it 'should ignore environment (RACK_ENV) for all workers' do
|
45
|
+
Sneakers.configure(:env => 'production')
|
46
|
+
Sneakers.not_environmental!
|
47
|
+
EnvWorker.new.queue.name.must_equal('defaults')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should ignore environment (RACK_ENV) for all workers' do
|
51
|
+
Sneakers.configure(:env => 'production')
|
52
|
+
EnvWorker.new.queue.name.must_equal('defaults_production')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
36
56
|
describe '.clear!' do
|
37
57
|
it 'must reset dirty configuration to default' do
|
38
58
|
Sneakers::Config[:log].must_equal(STDOUT)
|
@@ -91,6 +91,16 @@ class MetricsWorker
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
class WithParamsWorker
|
95
|
+
include Sneakers::Worker
|
96
|
+
from_queue 'defaults',
|
97
|
+
:ack => true,
|
98
|
+
:timeout_job_after => 0.5
|
99
|
+
|
100
|
+
def work_with_params(msg, header, props)
|
101
|
+
msg
|
102
|
+
end
|
103
|
+
end
|
94
104
|
|
95
105
|
|
96
106
|
class TestPool
|
@@ -124,8 +134,10 @@ end
|
|
124
134
|
describe Sneakers::Worker do
|
125
135
|
before do
|
126
136
|
@queue = Object.new
|
137
|
+
@exchange = Object.new
|
127
138
|
stub(@queue).name { 'test-queue' }
|
128
139
|
stub(@queue).opts { {} }
|
140
|
+
stub(@queue).exchange { @exchange }
|
129
141
|
|
130
142
|
Sneakers.configure(:env => 'test', :daemonize => true, :log => 'sneakers.log')
|
131
143
|
Sneakers::Worker.configure_logger(Logger.new('/dev/null'))
|
@@ -275,9 +287,8 @@ describe Sneakers::Worker do
|
|
275
287
|
describe 'publish' do
|
276
288
|
it 'should be able to publish a message from working context' do
|
277
289
|
w = PublishingWorker.new(@queue, TestPool.new)
|
278
|
-
mock(
|
290
|
+
mock(@exchange).publish('msg', :routing_key => 'target_test').once
|
279
291
|
w.do_work(nil, nil, 'msg', nil)
|
280
|
-
|
281
292
|
end
|
282
293
|
end
|
283
294
|
|
@@ -338,4 +349,27 @@ describe Sneakers::Worker do
|
|
338
349
|
end
|
339
350
|
end
|
340
351
|
|
352
|
+
|
353
|
+
|
354
|
+
describe 'With Params' do
|
355
|
+
before do
|
356
|
+
@handler = Object.new
|
357
|
+
stub(@handler).acknowledge("tag")
|
358
|
+
stub(@handler).reject("tag")
|
359
|
+
stub(@handler).timeout("tag")
|
360
|
+
stub(@handler).error("tag", anything)
|
361
|
+
stub(@handler).noop("tag")
|
362
|
+
|
363
|
+
@header = Object.new
|
364
|
+
stub(@header).delivery_tag { "tag" }
|
365
|
+
|
366
|
+
@w = WithParamsWorker.new(@queue, TestPool.new)
|
367
|
+
mock(@w.metrics).timing("work.WithParamsWorker.time").yields.once
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'should call work_with_params and not work' do
|
371
|
+
mock(@w).work_with_params(:ack, @header, {:foo => 1}).once
|
372
|
+
@w.do_work(@header, {:foo => 1 }, :ack, @handler)
|
373
|
+
end
|
374
|
+
end
|
341
375
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sneakers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0.pre
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Dotan Nahum
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-01-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: serverengine
|
@@ -32,17 +32,17 @@ dependencies:
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
|
-
- -
|
35
|
+
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 0.
|
37
|
+
version: 1.0.7
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 0.
|
45
|
+
version: 1.0.7
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: thread
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,11 +212,13 @@ extensions: []
|
|
212
212
|
extra_rdoc_files: []
|
213
213
|
files:
|
214
214
|
- .gitignore
|
215
|
+
- CHANGELOG.md
|
215
216
|
- Gemfile
|
216
217
|
- Gemfile.lock
|
217
218
|
- Guardfile
|
218
219
|
- LICENSE.txt
|
219
220
|
- README.md
|
221
|
+
- ROADMAP.md
|
220
222
|
- Rakefile
|
221
223
|
- bin/sneakers
|
222
224
|
- examples/benchmark_worker.rb
|
@@ -231,6 +233,7 @@ files:
|
|
231
233
|
- lib/sneakers/concerns/metrics.rb
|
232
234
|
- lib/sneakers/handlers/oneshot.rb
|
233
235
|
- lib/sneakers/metrics/logging_metrics.rb
|
236
|
+
- lib/sneakers/metrics/newrelic_metrics.rb
|
234
237
|
- lib/sneakers/metrics/null_metrics.rb
|
235
238
|
- lib/sneakers/metrics/statsd_metrics.rb
|
236
239
|
- lib/sneakers/publisher.rb
|
@@ -268,9 +271,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
268
271
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
269
272
|
none: false
|
270
273
|
requirements:
|
271
|
-
- - ! '
|
274
|
+
- - ! '>'
|
272
275
|
- !ruby/object:Gem::Version
|
273
|
-
version:
|
276
|
+
version: 1.3.1
|
274
277
|
requirements: []
|
275
278
|
rubyforge_project:
|
276
279
|
rubygems_version: 1.8.23
|