sneakers 0.0.7 → 0.1.0.pre
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/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
|