vx-lib-consumer 0.2.1

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.
@@ -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