vx-lib-consumer 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,210 @@
1
+ require 'json'
2
+ require 'timeout'
3
+ require 'spec_helper'
4
+
5
+ describe Vx::Lib::Consumer do
6
+
7
+ before do
8
+ Bob.timeout = 0.1
9
+ end
10
+
11
+ context "test consumer declaration" do
12
+ context "alice" do
13
+ subject { Alice.params }
14
+ its(:exchange_name) { should eq 'amq.fanout' }
15
+ its(:exchange_options) { should eq(durable: true, auto_delete: false, type: :fanout) }
16
+ its(:queue_name) { should eq '' }
17
+ its(:queue_options) { should eq(exclusive: false, durable: true, auto_delete: false) }
18
+ its(:ack) { should be_false }
19
+ its(:routing_key) { should eq 'mykey' }
20
+ its(:headers) { should be_nil }
21
+ its(:content_type) { should eq 'text/plain' }
22
+ end
23
+
24
+ context "bob" do
25
+ subject { Bob.params }
26
+ its(:exchange_name) { should eq 'bob_exch' }
27
+ its(:exchange_options) { should eq(durable: false, auto_delete: true, type: :topic) }
28
+ its(:queue_name) { should eq 'bob_queue' }
29
+ its(:queue_options) { should eq(durable: false, auto_delete: true) }
30
+ its(:ack) { should be_true }
31
+ its(:routing_key) { should be_nil }
32
+ its(:content_type) { should eq 'application/json' }
33
+ end
34
+ end
35
+
36
+ it "simple pub/sub" do
37
+ consumer = Bob.subscribe
38
+ sleep 1
39
+ 3.times {|n| Bob.publish("a" => n) }
40
+
41
+ Timeout.timeout(5) do
42
+ loop do
43
+ break if Bob._collected.size == 3
44
+ sleep 0.1
45
+ end
46
+ end
47
+
48
+ Timeout.timeout(3) do
49
+ consumer.graceful_shutdown
50
+ end
51
+
52
+ expect(Bob._collected).to eq([{"a"=>0}, {"a"=>1}, {"a"=>2}])
53
+ end
54
+
55
+ it "start/stop many times" do
56
+ fn = lambda do |idx|
57
+ consumer = Bob.subscribe
58
+ sleep 1
59
+ 3.times {|n| Bob.publish("a" => n + (3 * idx)) }
60
+
61
+ Timeout.timeout(5) do
62
+ loop do
63
+ break if Bob._collected.size == 3 + (3 * idx)
64
+ sleep 0.1
65
+ end
66
+ end
67
+ Timeout.timeout(3) do
68
+ consumer.graceful_shutdown
69
+ end
70
+
71
+ expect(consumer).to be_closed
72
+ end
73
+
74
+ 10.times do |n|
75
+ fn.call(n)
76
+ end
77
+
78
+ expect(Bob._collected.flat_map(&:values)).to eq((0..29).to_a)
79
+ end
80
+
81
+ it "pub/sub in multithreaded environment" do
82
+ handle_errors do
83
+ cns = []
84
+ 30.times do |n|
85
+ cns << Bob.subscribe
86
+ end
87
+
88
+ 90.times do |n|
89
+ Thread.new do
90
+ Bob.publish("a" => n)
91
+ end
92
+ end
93
+
94
+ Timeout.timeout(10) do
95
+ loop do
96
+ break if Bob._collected.size >= 90
97
+ sleep 0.1
98
+ end
99
+ end
100
+
101
+ Timeout.timeout(1) do
102
+ cns.map(&:graceful_shutdown)
103
+ end
104
+
105
+ expect(Bob._collected.map{|c| c["a"] }.uniq.sort).to eq((0...90).to_a)
106
+ end
107
+ end
108
+
109
+ it "should catch errors" do
110
+ error = nil
111
+ Vx::Lib::Consumer.configure do |c|
112
+ c.on_error do |e, env|
113
+ error = [e, env]
114
+ end
115
+ end
116
+ consumer = Bob.subscribe
117
+ sleep 0.1
118
+ Bob.publish "not json"
119
+
120
+ sleep 0.1
121
+ consumer.cancel
122
+
123
+ expect(error[0]).to be_an_instance_of(JSON::ParserError)
124
+ expect(error[1][:consumer]).to_not be_nil
125
+ end
126
+
127
+ it "should wait shutdown" do
128
+ bob1 = Bob.subscribe
129
+ bob2 = Bob.subscribe
130
+ Bob.publish a: 1
131
+ Bob.publish a: 2
132
+
133
+ th1 = bob1.wait_shutdown
134
+ th2 = bob2.wait_shutdown
135
+ sleep 0.2
136
+ Vx::Lib::Consumer.shutdown
137
+
138
+ Timeout.timeout(1) do
139
+ [th1, th2].map(&:join)
140
+ end
141
+
142
+ expect(Bob._collected.map(&:values).flatten.sort).to eq [1,2]
143
+ end
144
+
145
+ it "should work with graceful_shutdown" do
146
+ Bob.timeout = 1
147
+
148
+ consumer = Bob.subscribe
149
+ 10.times do |n|
150
+ Bob.publish a: n
151
+ end
152
+
153
+ sleep 0.1
154
+ Timeout.timeout(10) do
155
+ consumer.graceful_shutdown
156
+ end
157
+
158
+ expect(Bob._collected).to_not be_empty
159
+ end
160
+
161
+ it "should work with try_graceful_shutdown" do
162
+ Bob.timeout = 1
163
+
164
+ consumer = Bob.subscribe
165
+ 1.times do |n|
166
+ Bob.publish a: n
167
+ end
168
+
169
+ sleep 0.1
170
+ expect(consumer.try_graceful_shutdown).to be_false
171
+
172
+ Timeout.timeout(2) do
173
+ while consumer.running?
174
+ sleep 0.1
175
+ end
176
+ end
177
+
178
+ expect(consumer.try_graceful_shutdown).to be_true
179
+ end
180
+
181
+ it "running? should be true when consumer process task" do
182
+ Bob.timeout = 1
183
+ consumer = Bob.subscribe
184
+
185
+ expect(consumer.running?).to be_false
186
+
187
+ 10.times do |n|
188
+ Bob.publish a: n
189
+ end
190
+
191
+ sleep 0.1
192
+ expect(consumer.running?).to be_true
193
+
194
+ Timeout.timeout(1) do
195
+ consumer.cancel
196
+ end
197
+
198
+ sleep 0.1
199
+ expect(consumer.running?).to be_false
200
+ end
201
+
202
+ def handle_errors
203
+ begin
204
+ yield
205
+ rescue Exception => e
206
+ Vx::Lib::Consumer.exception_handler(e, {})
207
+ raise e
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,67 @@
1
+ require 'timeout'
2
+ require 'spec_helper'
3
+
4
+ describe Vx::Lib::Consumer, '(rpc)' do
5
+
6
+ it "simple rep/rep" do
7
+ sleep 1
8
+ consumer = Kenny.subscribe
9
+ sleep 1
10
+
11
+ re = Kenny.rpc.call(:kill, ['Oh'], timeout: 60)
12
+ expect(re).to eq 'rep: Oh'
13
+
14
+ Timeout.timeout(3) do
15
+ consumer.graceful_shutdown
16
+ end
17
+
18
+ Kenny.rpc.client.cancel
19
+ sleep 1
20
+ end
21
+
22
+ it "rep/rep in multithreaded environment" do
23
+ re = []
24
+ handle_errors do
25
+ cns = []
26
+ ths = []
27
+
28
+ 30.times do |n|
29
+ cns << Kenny.subscribe
30
+ end
31
+
32
+ idx = 0
33
+ 10.times do |i|
34
+ 100.times do |j|
35
+ idx += 1
36
+ n = "%08d" % idx
37
+ ths << Thread.new do
38
+ re << Kenny.rpc.call(:kill, [n])
39
+ end
40
+ end
41
+ sleep 0.1
42
+ end
43
+
44
+ Timeout.timeout(10) do
45
+ ths.map(&:join)
46
+ end
47
+
48
+ Timeout.timeout(10) do
49
+ cns.map(&:graceful_shutdown)
50
+ end
51
+
52
+ Kenny.rpc.client.cancel
53
+ sleep 1
54
+ end
55
+
56
+ expect(re.size).to eq 10 * 100
57
+ end
58
+
59
+ def handle_errors
60
+ begin
61
+ yield
62
+ rescue Exception => e
63
+ Vx::Lib::Consumer.exception_handler(e, {})
64
+ raise e
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,43 @@
1
+ require 'json'
2
+ require 'beefcake'
3
+ require 'spec_helper'
4
+
5
+ describe Vx::Lib::Consumer::Serializer do
6
+ let(:s) { described_class }
7
+
8
+ context "text/plain" do
9
+ let(:payload) { 'payload' }
10
+
11
+ it "should pack payload" do
12
+ expect(s.pack('text/plain', payload)).to eq 'payload'
13
+ end
14
+
15
+ it "should unpack payload" do
16
+ expect(s.unpack('text/plain', payload, nil)).to eq 'payload'
17
+ end
18
+ end
19
+
20
+ context "application/json" do
21
+ let(:payload) { {a: 1} }
22
+
23
+ it "should pack payload" do
24
+ expect(s.pack('application/json', payload)).to eq "{\"a\":1}"
25
+ end
26
+
27
+ it "should unpack payload" do
28
+ expect(s.unpack('application/json', payload.to_json, nil)).to eq("a"=>1)
29
+ end
30
+ end
31
+
32
+ context "application/x-protobuf" do
33
+ let(:payload) { BeefcakeTestMessage.new(x: 1, y: 2) }
34
+
35
+ it "should pack payload" do
36
+ expect(s.pack('application/x-protobuf', payload)).to eq payload.encode.to_s
37
+ end
38
+
39
+ it "should unpack payload" do
40
+ expect(s.unpack('application/x-protobuf', payload.encode.to_s, BeefcakeTestMessage)).to eq payload
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Vx::Lib::Consumer::Session do
4
+ let(:sess) { described_class.new }
5
+ subject { sess }
6
+
7
+ after do
8
+ sess.close
9
+ end
10
+
11
+ it { should be }
12
+
13
+ it "should successfuly open connection" do
14
+ expect {
15
+ sess.open
16
+ }.to change(sess, :open?).to(true)
17
+ end
18
+
19
+ it "should successfuly open connection in multithread environment" do
20
+ (0..10).map do |n|
21
+ Thread.new do
22
+ sess.open
23
+ end
24
+ end.map(&:value)
25
+
26
+ expect(sess).to be_open
27
+ end
28
+
29
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path '../../lib/vx/lib/consumer', __FILE__
2
+
3
+ Dir[File.expand_path("../..", __FILE__) + "/spec/support/**.rb"].each {|f| require f}
4
+
5
+ ENV['VX_CONSUMER_DEBUG'] = '1'
6
+
7
+ RSpec.configure do |config|
8
+
9
+ config.before(:each) do
10
+ Vx::Lib::Consumer.configuration.reset!
11
+ end
12
+
13
+ config.after(:each) do
14
+ Vx::Lib::Consumer.session.close
15
+ Bob._reset
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ require 'beefcake'
2
+
3
+ class BeefcakeTestMessage
4
+ include Beefcake::Message
5
+
6
+ required :x, :int32, 1
7
+ required :y, :int32, 2
8
+ end
@@ -0,0 +1,59 @@
1
+ require 'thread'
2
+
3
+ class Alice
4
+ include Vx::Lib::Consumer
5
+
6
+ content_type 'text/plain'
7
+ routing_key 'mykey'
8
+ fanout
9
+ end
10
+
11
+ class Kenny
12
+ include Vx::Lib::Consumer
13
+
14
+ class << self
15
+ def m_kill(value)
16
+ "rep: #{value}"
17
+ end
18
+ end
19
+
20
+ rpc.action :kill, method(:m_kill)
21
+ end
22
+
23
+ class Bob
24
+ include Vx::Lib::Consumer
25
+
26
+ exchange 'bob_exch', durable: false, auto_delete: true
27
+ queue 'bob_queue', durable: false, auto_delete: true
28
+ ack
29
+
30
+ @@m = Mutex.new
31
+ @@collected = []
32
+
33
+ class << self
34
+
35
+ attr_accessor :timeout
36
+
37
+ def _collected
38
+ @@collected
39
+ end
40
+
41
+ def _reset
42
+ @@m.synchronize do
43
+ @@collected = []
44
+ end
45
+ end
46
+
47
+ def _save(payload)
48
+ @@m.synchronize do
49
+ @@collected << payload
50
+ end
51
+ end
52
+ end
53
+
54
+ def perform(payload)
55
+ self.class._save payload
56
+ sleep self.class.timeout
57
+ ack
58
+ end
59
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'vx/lib/consumer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "vx-lib-consumer"
8
+ spec.version = Vx::Lib::Consumer::VERSION
9
+ spec.authors = ["Dmitry Galinsky"]
10
+ spec.email = ["dima.exe@gmail.com"]
11
+ spec.summary = %q{ summary }
12
+ spec.description = %q{ description }
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency 'bunny', '= 1.6.3'
22
+ spec.add_runtime_dependency 'vx-common-rack-builder', '>= 0.0.2'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.5"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec", '2.14.1'
27
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vx-lib-consumer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Dmitry Galinsky
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bunny
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.6.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.6.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: vx-common-rack-builder
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 2.14.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 2.14.1
83
+ description: " description "
84
+ email:
85
+ - dima.exe@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - LICENSE.txt
95
+ - README.md
96
+ - Rakefile
97
+ - lib/vx/lib/consumer.rb
98
+ - lib/vx/lib/consumer/ack.rb
99
+ - lib/vx/lib/consumer/configuration.rb
100
+ - lib/vx/lib/consumer/error.rb
101
+ - lib/vx/lib/consumer/instrument.rb
102
+ - lib/vx/lib/consumer/params.rb
103
+ - lib/vx/lib/consumer/publish.rb
104
+ - lib/vx/lib/consumer/rpc.rb
105
+ - lib/vx/lib/consumer/serializer.rb
106
+ - lib/vx/lib/consumer/session.rb
107
+ - lib/vx/lib/consumer/subscribe.rb
108
+ - lib/vx/lib/consumer/subscriber.rb
109
+ - lib/vx/lib/consumer/testing.rb
110
+ - lib/vx/lib/consumer/version.rb
111
+ - spec/lib/consumer_spec.rb
112
+ - spec/lib/rpc_spec.rb
113
+ - spec/lib/serializer_spec.rb
114
+ - spec/lib/session_spec.rb
115
+ - spec/spec_helper.rb
116
+ - spec/support/beefcake_test_message.rb
117
+ - spec/support/test_consumers.rb
118
+ - vx-lib-consumer.gemspec
119
+ homepage: ''
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubyforge_project:
139
+ rubygems_version: 2.2.2
140
+ signing_key:
141
+ specification_version: 4
142
+ summary: summary
143
+ test_files:
144
+ - spec/lib/consumer_spec.rb
145
+ - spec/lib/rpc_spec.rb
146
+ - spec/lib/serializer_spec.rb
147
+ - spec/lib/session_spec.rb
148
+ - spec/spec_helper.rb
149
+ - spec/support/beefcake_test_message.rb
150
+ - spec/support/test_consumers.rb