protobuf 2.8.0 → 2.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +8 -0
- data/Rakefile +2 -16
- data/lib/protobuf/rpc/connectors/common.rb +2 -0
- data/lib/protobuf/rpc/connectors/socket.rb +0 -1
- data/lib/protobuf/rpc/connectors/zmq.rb +0 -1
- data/lib/protobuf/rpc/server.rb +1 -0
- data/lib/protobuf/rpc/servers/evented/server.rb +0 -1
- data/lib/protobuf/rpc/servers/socket/worker.rb +0 -2
- data/lib/protobuf/rpc/service_directory.rb +105 -83
- data/lib/protobuf/rpc/stat.rb +13 -5
- data/lib/protobuf/version.rb +2 -2
- data/protobuf.gemspec +1 -1
- data/spec/lib/protobuf/code_generator_spec.rb +2 -2
- data/spec/lib/protobuf/generators/base_spec.rb +3 -3
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +3 -3
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +216 -133
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +2 -2
- data/spec/lib/protobuf/rpc/stat_spec.rb +70 -0
- data/spec/support/test/google_unittest.pb.rb +0 -2
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d622f286e789d42300ea06beabd355cdab3530e
|
4
|
+
data.tar.gz: 6d4a9e0fe5fc77d8bd8c65eec0befba2ff6cf9c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2aa2229e5701441dce3d776080f00f3306796440e55f7b085cafa03539fcbc1e35c0067d5d14de7d0285ebbdced0b708cd854b88579af2330974a587dd6e012e
|
7
|
+
data.tar.gz: 2080bb81394099f161a98ec44622f54343333ac3381a09da2d327041d7f46fae9b2c45a1ed0936bac9dd5ce96e442afa13b6ffbc9c9b7750182448e7f3aedbda
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
2.8.1
|
2
|
+
----------
|
3
|
+
|
4
|
+
- Improve `ServiceDirectory` lookup speed ~10x, lookups now done in constant time (devin-c).
|
5
|
+
- Add Timestamp to end of rpc stat log (represents ending time of request processing).
|
6
|
+
- Set `request_size` in the rpc stat within ZMQ Worker (previously missing).
|
7
|
+
- Ensure `request_size` and `response_size` are set on rpc stat for client requests.
|
8
|
+
|
1
9
|
2.8.0
|
2
10
|
-----------
|
3
11
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
$: << ::File.expand_path('../', __FILE__)
|
2
|
+
$: << ::File.expand_path('../spec', __FILE__)
|
3
3
|
|
4
4
|
require "rubygems"
|
5
5
|
require "rubygems/package_task"
|
@@ -13,17 +13,3 @@ task :default => :spec
|
|
13
13
|
|
14
14
|
desc "Run specs"
|
15
15
|
RSpec::Core::RakeTask.new(:spec)
|
16
|
-
|
17
|
-
##
|
18
|
-
# rake-compiler
|
19
|
-
#
|
20
|
-
spec = Gem::Specification.load("protobuf.gemspec")
|
21
|
-
|
22
|
-
Gem::PackageTask.new(spec) do |pkg|
|
23
|
-
end
|
24
|
-
|
25
|
-
if RUBY_PLATFORM =~ /java/
|
26
|
-
require "rake/javaextensiontask"
|
27
|
-
else
|
28
|
-
require "rake/extensiontask"
|
29
|
-
end
|
@@ -74,6 +74,7 @@ module Protobuf
|
|
74
74
|
log_debug { sign_message("Parsing response from server (connection closed)") }
|
75
75
|
|
76
76
|
# Parse out the raw response
|
77
|
+
@stats.response_size = @response_data.size
|
77
78
|
response_wrapper = Protobuf::Socketrpc::Response.decode(@response_data)
|
78
79
|
|
79
80
|
# Determine success or failure based on parsed data
|
@@ -120,6 +121,7 @@ module Protobuf
|
|
120
121
|
def setup_connection
|
121
122
|
initialize_stats
|
122
123
|
@request_data = request_bytes
|
124
|
+
@stats.request_size = request_bytes.size
|
123
125
|
end
|
124
126
|
|
125
127
|
def succeed(response)
|
@@ -55,7 +55,6 @@ module Protobuf
|
|
55
55
|
return if error?
|
56
56
|
response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
|
57
57
|
response_buffer << read_data
|
58
|
-
@stats.response_size = response_buffer.size
|
59
58
|
@response_data = response_buffer.data
|
60
59
|
parse_response if response_buffer.flushed?
|
61
60
|
end
|
data/lib/protobuf/rpc/server.rb
CHANGED
@@ -67,6 +67,7 @@ module Protobuf
|
|
67
67
|
# Parse the incoming request object into our expected request object
|
68
68
|
def parse_request_from_buffer
|
69
69
|
log_debug { sign_message("Parsing request from buffer: #{@request_data}") }
|
70
|
+
@stats.request_size = @request_data.size
|
70
71
|
@request.decode(@request_data)
|
71
72
|
rescue => error
|
72
73
|
exc = ::Protobuf::Rpc::BadRequestData.new("Unable to parse request: #{error.message}")
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
require 'singleton'
|
3
3
|
require 'socket'
|
4
|
+
require 'set'
|
4
5
|
require 'thread'
|
5
6
|
require 'timeout'
|
6
7
|
|
@@ -21,20 +22,32 @@ module Protobuf
|
|
21
22
|
attr_reader :expires_at
|
22
23
|
|
23
24
|
def initialize(server)
|
24
|
-
|
25
|
-
@expires_at = Time.now.to_i + ttl
|
25
|
+
update(server)
|
26
26
|
end
|
27
27
|
|
28
28
|
def current?
|
29
29
|
!expired?
|
30
30
|
end
|
31
31
|
|
32
|
+
def eql?(other)
|
33
|
+
uuid.eql?(other.uuid)
|
34
|
+
end
|
35
|
+
|
32
36
|
def expired?
|
33
37
|
Time.now.to_i >= @expires_at
|
34
38
|
end
|
35
39
|
|
40
|
+
def hash
|
41
|
+
uuid.hash
|
42
|
+
end
|
43
|
+
|
36
44
|
def ttl
|
37
|
-
[super.to_i,
|
45
|
+
[super.to_i, 1].max
|
46
|
+
end
|
47
|
+
|
48
|
+
def update(server)
|
49
|
+
@server = server
|
50
|
+
@expires_at = Time.now.to_i + ttl
|
38
51
|
end
|
39
52
|
|
40
53
|
def __getobj__
|
@@ -65,70 +78,22 @@ module Protobuf
|
|
65
78
|
self.instance.stop
|
66
79
|
end
|
67
80
|
|
81
|
+
#
|
68
82
|
# Instance Methods
|
69
83
|
#
|
70
84
|
def initialize
|
71
|
-
|
72
|
-
@mutex = Mutex.new
|
73
|
-
end
|
74
|
-
|
75
|
-
def add_listing_for(server)
|
76
|
-
if server && server.uuid
|
77
|
-
@mutex.synchronize do
|
78
|
-
action = @listings.key?(server.uuid) ? :updated : :added
|
79
|
-
log_debug { sign_message("#{action} server: #{server.inspect}") }
|
80
|
-
|
81
|
-
listing = Listing.new(server)
|
82
|
-
@listings[server.uuid] = listing
|
83
|
-
trigger(action, listing)
|
84
|
-
end
|
85
|
-
else
|
86
|
-
log_info { sign_message("Cannot add server without uuid: #{server.inspect}") }
|
87
|
-
end
|
85
|
+
reset
|
88
86
|
end
|
89
87
|
|
90
88
|
def each_listing(&block)
|
91
|
-
@
|
89
|
+
@listings_by_uuid.each_value(&block)
|
92
90
|
end
|
93
91
|
|
94
92
|
def lookup(service)
|
95
93
|
if running?
|
96
|
-
@
|
97
|
-
|
98
|
-
listing.services.any? do |listed_service|
|
99
|
-
listing.current? && listed_service == service.to_s
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
listings.sample
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def remove_expired_listings
|
109
|
-
@mutex.synchronize do
|
110
|
-
@listings.delete_if do |uuid, listing|
|
111
|
-
if listing.expired?
|
112
|
-
trigger(:removed, listing)
|
113
|
-
true
|
114
|
-
else
|
115
|
-
false
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def remove_listing_for(server)
|
122
|
-
if server && server.uuid
|
123
|
-
log_debug { sign_message("Removing server: #{server.inspect}") }
|
124
|
-
|
125
|
-
@mutex.synchronize do
|
126
|
-
deleted_listing = @listings.delete(server.uuid)
|
127
|
-
trigger(:removed, deleted_listing)
|
94
|
+
if @listings_by_service.key?(service)
|
95
|
+
@listings_by_service[service].entries.sample
|
128
96
|
end
|
129
|
-
|
130
|
-
else
|
131
|
-
log_info { sign_message("Cannot remove server without uuid: #{server.inspect}") }
|
132
97
|
end
|
133
98
|
end
|
134
99
|
|
@@ -154,18 +119,34 @@ module Protobuf
|
|
154
119
|
def stop
|
155
120
|
log_info { sign_message("Stopping directory") }
|
156
121
|
|
157
|
-
@
|
158
|
-
@thread.try(:kill)
|
159
|
-
@thread = nil
|
160
|
-
@listings = {}
|
161
|
-
end
|
162
|
-
|
122
|
+
@thread.try(:kill).try(:join)
|
163
123
|
@socket.try(:close)
|
164
|
-
|
124
|
+
|
125
|
+
reset
|
165
126
|
end
|
166
127
|
|
167
128
|
private
|
168
129
|
|
130
|
+
def add_or_update_listing(uuid, server)
|
131
|
+
listing = @listings_by_uuid[uuid]
|
132
|
+
|
133
|
+
if listing
|
134
|
+
action = :updated
|
135
|
+
listing.update(server)
|
136
|
+
else
|
137
|
+
action = :added
|
138
|
+
listing = Listing.new(server)
|
139
|
+
@listings_by_uuid[uuid] = listing
|
140
|
+
end
|
141
|
+
|
142
|
+
listing.services.each do |service|
|
143
|
+
@listings_by_service[service] << listing
|
144
|
+
end
|
145
|
+
|
146
|
+
trigger(action, listing)
|
147
|
+
log_debug { sign_message("#{action} server: #{server.inspect}") }
|
148
|
+
end
|
149
|
+
|
169
150
|
def init_socket
|
170
151
|
@socket = UDPSocket.new
|
171
152
|
@socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
|
@@ -178,39 +159,80 @@ module Protobuf
|
|
178
159
|
end
|
179
160
|
|
180
161
|
def process_beacon(beacon)
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
162
|
+
server = beacon.server
|
163
|
+
uuid = server.try(:uuid)
|
164
|
+
|
165
|
+
if server && uuid
|
166
|
+
case beacon.beacon_type
|
167
|
+
when ::Protobuf::Rpc::DynamicDiscovery::BeaconType::HEARTBEAT
|
168
|
+
add_or_update_listing(uuid, server)
|
169
|
+
when ::Protobuf::Rpc::DynamicDiscovery::BeaconType::FLATLINE
|
170
|
+
remove_listing(uuid)
|
171
|
+
end
|
172
|
+
else
|
173
|
+
log_info { sign_message("Ignoring incomplete beacon: #{beacon.inspect}") }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def read_beacon
|
178
|
+
data, addr = @socket.recvfrom(2048)
|
179
|
+
|
180
|
+
beacon = ::Protobuf::Rpc::DynamicDiscovery::Beacon.decode(data)
|
181
|
+
|
182
|
+
# Favor the address captured by the socket
|
183
|
+
beacon.try(:server).try(:address=, addr[3])
|
184
|
+
|
185
|
+
beacon
|
186
|
+
end
|
187
|
+
|
188
|
+
def remove_expired_listings
|
189
|
+
log_debug { sign_message("Removing expired listings") }
|
190
|
+
@listings_by_uuid.each do |uuid, listing|
|
191
|
+
remove_listing(uuid) if listing.expired?
|
186
192
|
end
|
187
193
|
end
|
188
194
|
|
195
|
+
def remove_listing(uuid)
|
196
|
+
listing = @listings_by_uuid[uuid] or return
|
197
|
+
|
198
|
+
log_debug { sign_message("Removing listing: #{listing.inspect}") }
|
199
|
+
|
200
|
+
@listings_by_service.each do |service, listings|
|
201
|
+
listings.delete(listing)
|
202
|
+
end
|
203
|
+
|
204
|
+
trigger(:removed, @listings_by_uuid.delete(uuid))
|
205
|
+
end
|
206
|
+
|
207
|
+
def reset
|
208
|
+
@thread = nil
|
209
|
+
@socket = nil
|
210
|
+
@listings_by_uuid = {}
|
211
|
+
@listings_by_service = Hash.new { |h, k| h[k] = Set.new }
|
212
|
+
end
|
213
|
+
|
189
214
|
def run
|
215
|
+
sweep_interval = 1 # sweep expired listings every 1 second
|
216
|
+
next_sweep = Time.now.to_i + sweep_interval
|
217
|
+
|
190
218
|
loop do
|
191
|
-
|
192
|
-
|
193
|
-
|
219
|
+
timeout = [next_sweep - Time.now.to_i, 0.1].max
|
220
|
+
readable = IO.select([@socket], nil, nil, timeout)
|
221
|
+
process_beacon(read_beacon) if readable
|
222
|
+
|
223
|
+
if Time.now.to_i >= next_sweep
|
224
|
+
remove_expired_listings
|
225
|
+
next_sweep = Time.now.to_i + sweep_interval
|
226
|
+
end
|
194
227
|
end
|
195
228
|
rescue => e
|
196
|
-
log_debug { sign_message("
|
229
|
+
log_debug { sign_message("ERROR: (#{e.class}) #{e.message}\n#{e.backtrace.join("\n")}") }
|
197
230
|
retry
|
198
231
|
end
|
199
232
|
|
200
233
|
def trigger(action, listing)
|
201
234
|
::Protobuf::Lifecycle.trigger("directory.listing.#{action}", listing)
|
202
235
|
end
|
203
|
-
|
204
|
-
def wait_for_beacon
|
205
|
-
data, addr = @socket.recvfrom(2048)
|
206
|
-
|
207
|
-
beacon = ::Protobuf::Rpc::DynamicDiscovery::Beacon.decode(data)
|
208
|
-
|
209
|
-
# Favor the address captured by the socket
|
210
|
-
beacon.try(:server).try(:address=, addr[3])
|
211
|
-
|
212
|
-
beacon
|
213
|
-
end
|
214
236
|
end
|
215
237
|
end
|
216
238
|
end
|
data/lib/protobuf/rpc/stat.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'date'
|
2
|
+
require 'time'
|
2
3
|
require 'protobuf/logger'
|
3
4
|
|
4
5
|
module Protobuf
|
@@ -11,6 +12,8 @@ module Protobuf
|
|
11
12
|
|
12
13
|
def initialize(mode = :SERVER)
|
13
14
|
@mode = mode
|
15
|
+
@request_size = 0
|
16
|
+
@response_size = 0
|
14
17
|
start
|
15
18
|
end
|
16
19
|
|
@@ -43,16 +46,20 @@ module Protobuf
|
|
43
46
|
end
|
44
47
|
|
45
48
|
def sizes
|
46
|
-
|
49
|
+
if stopped?
|
50
|
+
"#{@request_size}B/#{@response_size}B"
|
51
|
+
else
|
52
|
+
"#{@request_size}B/-"
|
53
|
+
end
|
47
54
|
end
|
48
55
|
|
49
56
|
def start
|
50
|
-
@start_time ||= Time.now
|
57
|
+
@start_time ||= ::Time.now
|
51
58
|
end
|
52
59
|
|
53
60
|
def stop
|
54
61
|
start unless @start_time
|
55
|
-
@end_time ||= Time.now
|
62
|
+
@end_time ||= ::Time.now
|
56
63
|
end
|
57
64
|
|
58
65
|
def stopped?
|
@@ -77,13 +84,14 @@ module Protobuf
|
|
77
84
|
server? ? client : server,
|
78
85
|
trace_id,
|
79
86
|
rpc,
|
87
|
+
sizes,
|
80
88
|
elapsed_time,
|
81
|
-
|
89
|
+
@end_time.try(:iso8601)
|
82
90
|
].compact.join(' - ')
|
83
91
|
end
|
84
92
|
|
85
93
|
def trace_id
|
86
|
-
Thread.current.object_id.to_s(16)
|
94
|
+
::Thread.current.object_id.to_s(16)
|
87
95
|
end
|
88
96
|
|
89
97
|
end
|
data/lib/protobuf/version.rb
CHANGED
data/protobuf.gemspec
CHANGED
@@ -27,9 +27,9 @@ require "protobuf/version"
|
|
27
27
|
s.add_development_dependency 'ffi-rzmq'
|
28
28
|
s.add_development_dependency 'pry-nav'
|
29
29
|
s.add_development_dependency 'rake'
|
30
|
-
s.add_development_dependency 'rake-compiler'
|
31
30
|
s.add_development_dependency 'rspec'
|
32
31
|
s.add_development_dependency 'simplecov'
|
33
32
|
s.add_development_dependency 'yard'
|
33
|
+
s.add_development_dependency 'timecop'
|
34
34
|
# s.add_development_dependency 'perftools.rb'
|
35
35
|
end
|
@@ -15,8 +15,8 @@ describe ::Protobuf::CodeGenerator do
|
|
15
15
|
let(:output_file1) { COMPILER::CodeGeneratorResponse::File.new(:name => 'test/foo.pb.rb') }
|
16
16
|
let(:output_file2) { COMPILER::CodeGeneratorResponse::File.new(:name => 'test/bar.pb.rb') }
|
17
17
|
|
18
|
-
let(:file_generator1) {
|
19
|
-
let(:file_generator2) {
|
18
|
+
let(:file_generator1) { double('file generator 1', :generate_output_file => output_file1) }
|
19
|
+
let(:file_generator2) { double('file generator 2', :generate_output_file => output_file2) }
|
20
20
|
|
21
21
|
let(:request_bytes) do
|
22
22
|
COMPILER::CodeGeneratorRequest.encode(:proto_file => [ input_file1, input_file2 ])
|
@@ -5,10 +5,10 @@ require 'protobuf/generators/base'
|
|
5
5
|
|
6
6
|
describe ::Protobuf::Generators::Base do
|
7
7
|
|
8
|
-
subject { described_class.new(
|
8
|
+
subject { described_class.new(double) }
|
9
9
|
|
10
10
|
context 'namespaces' do
|
11
|
-
let(:descriptor) {
|
11
|
+
let(:descriptor) { double(:name => 'Baz') }
|
12
12
|
subject { described_class.new(descriptor, 0, :namespace => [ :foo, :bar ]) }
|
13
13
|
its(:type_namespace) { should eq [ :foo, :bar, 'Baz' ] }
|
14
14
|
its(:fully_qualified_type_namespace) { should eq '.foo.bar.Baz' }
|
@@ -55,7 +55,7 @@ describe ::Protobuf::Generators::Base do
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
subject { ToStringTest.new(
|
58
|
+
subject { ToStringTest.new(double) }
|
59
59
|
|
60
60
|
it 'compiles and returns the contents' do
|
61
61
|
10.times do
|
@@ -7,9 +7,9 @@ describe ::Protobuf::Generators::ExtensionGenerator do
|
|
7
7
|
|
8
8
|
let(:field_descriptors) {
|
9
9
|
[
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
double('field descriptor 1', :to_s => " field 1\n"),
|
11
|
+
double('field descriptor 2', :to_s => " field 2\n"),
|
12
|
+
double('field descriptor 3', :to_s => " field 3\n")
|
13
13
|
]
|
14
14
|
}
|
15
15
|
let(:message_type) { 'FooBar' }
|
@@ -12,20 +12,20 @@ describe ::Protobuf::Rpc::Connectors::Zmq do
|
|
12
12
|
:port => "9400"
|
13
13
|
}}
|
14
14
|
|
15
|
-
let(:
|
16
|
-
sm =
|
15
|
+
let(:socket_double) do
|
16
|
+
sm = double(::ZMQ::Socket)
|
17
17
|
sm.stub(:connect).and_return(0)
|
18
18
|
sm
|
19
19
|
end
|
20
20
|
|
21
|
-
let(:
|
22
|
-
zc =
|
23
|
-
zc.stub(:socket).and_return(
|
21
|
+
let(:zmq_context_double) do
|
22
|
+
zc = double(::ZMQ::Context)
|
23
|
+
zc.stub(:socket).and_return(socket_double)
|
24
24
|
zc
|
25
25
|
end
|
26
26
|
|
27
27
|
before do
|
28
|
-
::ZMQ::Context.stub(:new).and_return(
|
28
|
+
::ZMQ::Context.stub(:new).and_return(zmq_context_double)
|
29
29
|
end
|
30
30
|
|
31
31
|
describe "#lookup_server_uri" do
|
@@ -3,185 +3,268 @@ require 'spec_helper'
|
|
3
3
|
require 'protobuf/rpc/service_directory'
|
4
4
|
|
5
5
|
describe ::Protobuf::Rpc::ServiceDirectory do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
subject { described_class.instance }
|
7
|
+
|
8
|
+
let(:echo_server) {
|
9
|
+
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
10
|
+
:uuid => 'echo',
|
11
|
+
:address => '127.0.0.1',
|
12
|
+
:port => '1111',
|
13
|
+
:ttl => 10,
|
14
|
+
:services => %w[EchoService]
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:hello_server) {
|
19
|
+
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
20
|
+
:uuid => "hello",
|
21
|
+
:address => '127.0.0.1',
|
22
|
+
:port => "1112",
|
23
|
+
:ttl => 10,
|
24
|
+
:services => %w[HelloService]
|
25
|
+
)
|
26
|
+
}
|
27
|
+
|
28
|
+
let(:hello_server_with_short_ttl) {
|
29
|
+
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
30
|
+
:uuid => "hello_server_with_short_ttl",
|
31
|
+
:address => '127.0.0.1',
|
32
|
+
:port => '1113',
|
33
|
+
:ttl => 1,
|
34
|
+
:services => %w[HelloService]
|
35
|
+
)
|
36
|
+
}
|
37
|
+
|
38
|
+
let(:combo_server) {
|
39
|
+
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
40
|
+
:uuid => "combo",
|
41
|
+
:address => '127.0.0.1',
|
42
|
+
:port => '1114',
|
43
|
+
:ttl => 10,
|
44
|
+
:services => %w[HelloService EchoService]
|
45
|
+
)
|
46
|
+
}
|
47
|
+
|
48
|
+
before(:all) do
|
49
|
+
@address = "127.0.0.1"
|
50
|
+
@port = 33333
|
51
|
+
@socket = UDPSocket.new
|
52
|
+
|
53
|
+
described_class.address = @address
|
54
|
+
described_class.port = @port
|
10
55
|
end
|
11
56
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
57
|
+
def expect_event_trigger(event)
|
58
|
+
::Protobuf::Lifecycle
|
59
|
+
.should_receive(:trigger)
|
60
|
+
.with(event,
|
61
|
+
an_instance_of(::Protobuf::Rpc::ServiceDirectory::Listing))
|
62
|
+
.once
|
16
63
|
end
|
17
64
|
|
18
|
-
|
19
|
-
|
65
|
+
def send_beacon(type, server)
|
66
|
+
type = type.to_s.upcase
|
67
|
+
beacon = ::Protobuf::Rpc::DynamicDiscovery::Beacon.new(
|
68
|
+
:server => server,
|
69
|
+
:beacon_type => ::Protobuf::Rpc::DynamicDiscovery::BeaconType.fetch(type)
|
70
|
+
)
|
71
|
+
|
72
|
+
@socket.send(beacon.encode, 0, @address, @port)
|
73
|
+
sleep 0.01 # give the service directory time to process the beacon
|
20
74
|
end
|
21
75
|
|
22
|
-
it "
|
23
|
-
|
76
|
+
it "should be a singleton" do
|
77
|
+
subject.should be_a_kind_of(Singleton)
|
24
78
|
end
|
25
79
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
:address => "0.0.0.0",
|
30
|
-
:port => 9999,
|
31
|
-
:ttl => 15) }
|
32
|
-
let(:listing) { ::Protobuf::Rpc::ServiceDirectory::Listing.new(server) }
|
80
|
+
it "should be configured to listen to address 127.0.0.1" do
|
81
|
+
described_class.address.should eq '127.0.0.1'
|
82
|
+
end
|
33
83
|
|
34
|
-
|
35
|
-
|
36
|
-
|
84
|
+
it "should be configured to listen to port 33333" do
|
85
|
+
described_class.port.should eq 33333
|
86
|
+
end
|
37
87
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
88
|
+
it "should defer .start to the instance#start" do
|
89
|
+
described_class.instance.should_receive(:start)
|
90
|
+
described_class.start
|
91
|
+
end
|
42
92
|
|
43
|
-
|
44
|
-
|
45
|
-
|
93
|
+
it "should yeild itself to blocks passed to .start" do
|
94
|
+
described_class.instance.stub(:start)
|
95
|
+
expect { |b| described_class.start(&b) }.to yield_with_args(described_class)
|
96
|
+
end
|
46
97
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
98
|
+
it "should defer .stop to the instance#stop" do
|
99
|
+
described_class.instance.should_receive(:stop)
|
100
|
+
described_class.stop
|
101
|
+
end
|
51
102
|
|
52
|
-
|
53
|
-
|
54
|
-
'1' => double(:current? => false, :services => ["Test"]),
|
55
|
-
})
|
103
|
+
context "stopped" do
|
104
|
+
before { subject.stop }
|
56
105
|
|
57
|
-
|
106
|
+
describe "#lookup" do
|
107
|
+
it "should return nil" do
|
108
|
+
send_beacon(:heartbeat, echo_server)
|
109
|
+
subject.lookup("EchoService").should be_nil
|
110
|
+
end
|
58
111
|
end
|
59
|
-
end
|
60
112
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
:ttl => 15 }) }
|
67
|
-
|
68
|
-
it 'adds the listing to the known @listings' do
|
69
|
-
expect {
|
70
|
-
::Protobuf::Lifecycle.should_receive(:trigger)
|
71
|
-
.with('directory.listing.added', an_instance_of(::Protobuf::Rpc::ServiceDirectory::Listing))
|
72
|
-
.once
|
73
|
-
instance.add_listing_for(server)
|
74
|
-
}.to change(listings, :size).from(0).to(1)
|
113
|
+
describe "#restart" do
|
114
|
+
it "should start the service" do
|
115
|
+
subject.restart
|
116
|
+
subject.should be_running
|
117
|
+
end
|
75
118
|
end
|
76
|
-
end
|
77
|
-
|
78
|
-
describe '#each_listing' do
|
79
|
-
let(:listing_doubles) { { '1' => double('listing 1'),
|
80
|
-
'2' => double('listing 2'),
|
81
|
-
'3' => double('listing 3') } }
|
82
119
|
|
83
|
-
|
84
|
-
|
120
|
+
describe "#running" do
|
121
|
+
it "should be false" do
|
122
|
+
subject.should_not be_running
|
123
|
+
end
|
85
124
|
end
|
86
125
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
yielded_listings << listing
|
126
|
+
describe "#stop" do
|
127
|
+
it "has no effect" do
|
128
|
+
subject.stop
|
91
129
|
end
|
92
|
-
yielded_listings.should eq(listing_doubles.values)
|
93
130
|
end
|
94
131
|
end
|
95
132
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
'3' => double(:expired? => false) } }
|
133
|
+
context "started" do
|
134
|
+
before { subject.start }
|
135
|
+
after { subject.stop }
|
100
136
|
|
101
|
-
|
102
|
-
instance.instance_variable_set(:@listings, listing_doubles)
|
103
|
-
end
|
137
|
+
it { should be_running }
|
104
138
|
|
105
|
-
it "
|
106
|
-
|
107
|
-
|
108
|
-
.with('directory.listing.removed', an_instance_of(RSpec::Mocks::Mock))
|
109
|
-
.twice
|
110
|
-
instance.remove_expired_listings
|
111
|
-
}.to change(listings, :size).from(3).to(1)
|
112
|
-
listings.keys.should eq ['3']
|
139
|
+
it "should trigger added events" do
|
140
|
+
expect_event_trigger("directory.listing.added")
|
141
|
+
send_beacon(:heartbeat, echo_server)
|
113
142
|
end
|
114
|
-
end
|
115
143
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
144
|
+
it "should trigger updated events" do
|
145
|
+
send_beacon(:heartbeat, echo_server)
|
146
|
+
expect_event_trigger("directory.listing.updated")
|
147
|
+
send_beacon(:heartbeat, echo_server)
|
120
148
|
end
|
121
149
|
|
122
|
-
it "
|
123
|
-
|
124
|
-
|
150
|
+
it "should trigger removed events" do
|
151
|
+
send_beacon(:heartbeat, echo_server)
|
152
|
+
expect_event_trigger("directory.listing.removed")
|
153
|
+
send_beacon(:flatline, echo_server)
|
125
154
|
end
|
126
155
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
156
|
+
describe "#each_listing" do
|
157
|
+
it "should yield to a block for each listing" do
|
158
|
+
send_beacon(:heartbeat, hello_server)
|
159
|
+
send_beacon(:heartbeat, echo_server)
|
160
|
+
send_beacon(:heartbeat, combo_server)
|
132
161
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
162
|
+
expect { |block|
|
163
|
+
subject.each_listing(&block)
|
164
|
+
}.to yield_control.exactly(3).times
|
165
|
+
end
|
137
166
|
end
|
138
|
-
end
|
139
167
|
|
140
|
-
|
141
|
-
|
168
|
+
describe "#lookup" do
|
169
|
+
it "should provide listings by service" do
|
170
|
+
send_beacon(:heartbeat, hello_server)
|
171
|
+
subject.lookup("HelloService").to_hash.should eq hello_server.to_hash
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should return random listings" do
|
175
|
+
send_beacon(:heartbeat, hello_server)
|
176
|
+
send_beacon(:heartbeat, combo_server)
|
177
|
+
|
178
|
+
uuids = 100.times.map { subject.lookup("HelloService").uuid }
|
179
|
+
uuids.count("hello").should be_within(25).of(50)
|
180
|
+
uuids.count("combo").should be_within(25).of(50)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should not return expired listings" do
|
184
|
+
send_beacon(:heartbeat, hello_server_with_short_ttl)
|
185
|
+
sleep 1
|
186
|
+
subject.lookup("HelloService").should be_nil
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should not return flatlined servers" do
|
190
|
+
send_beacon(:heartbeat, echo_server)
|
191
|
+
send_beacon(:heartbeat, combo_server)
|
192
|
+
send_beacon(:flatline, echo_server)
|
193
|
+
|
194
|
+
uuids = 100.times.map { subject.lookup("EchoService").uuid }
|
195
|
+
uuids.count("combo").should eq 100
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should return up-to-date listings" do
|
199
|
+
send_beacon(:heartbeat, echo_server)
|
200
|
+
echo_server.port = "7777"
|
201
|
+
send_beacon(:heartbeat, echo_server)
|
142
202
|
|
143
|
-
|
144
|
-
|
203
|
+
subject.lookup("EchoService").port.should eq "7777"
|
204
|
+
end
|
145
205
|
end
|
146
206
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
207
|
+
describe "#restart" do
|
208
|
+
it "should clear all listings" do
|
209
|
+
send_beacon(:heartbeat, echo_server)
|
210
|
+
send_beacon(:heartbeat, combo_server)
|
211
|
+
subject.restart
|
212
|
+
subject.lookup("EchoService").should be_nil
|
151
213
|
end
|
214
|
+
end
|
152
215
|
|
153
|
-
|
216
|
+
describe "#running" do
|
217
|
+
it "should be true" do
|
218
|
+
subject.should be_running
|
219
|
+
end
|
154
220
|
end
|
155
221
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
:
|
160
|
-
|
161
|
-
|
162
|
-
|
222
|
+
describe "#stop" do
|
223
|
+
it "should clear all listings" do
|
224
|
+
send_beacon(:heartbeat, echo_server)
|
225
|
+
send_beacon(:heartbeat, combo_server)
|
226
|
+
subject.stop
|
227
|
+
subject.lookup("EchoService").should be_nil
|
228
|
+
end
|
163
229
|
|
164
|
-
it "
|
165
|
-
|
166
|
-
|
167
|
-
socket.send(payload, 0)
|
168
|
-
sleep 0.01
|
230
|
+
it "should stop the server" do
|
231
|
+
subject.stop
|
232
|
+
subject.should_not be_running
|
169
233
|
end
|
170
234
|
end
|
235
|
+
end
|
236
|
+
|
237
|
+
if ENV.key?("BENCH")
|
238
|
+
context "performance" do
|
239
|
+
let(:servers) {
|
240
|
+
100.times.collect do |x|
|
241
|
+
::Protobuf::Rpc::DynamicDiscovery::Server.new(
|
242
|
+
:uuid => server_name = "performance_server#{x + 1}",
|
243
|
+
:address => '127.0.0.1',
|
244
|
+
:port => (5555 + x).to_s,
|
245
|
+
:ttl => rand(1..5),
|
246
|
+
:services => 10.times.collect { |y| "PerformanceService#{y}" }
|
247
|
+
)
|
248
|
+
end
|
249
|
+
}
|
250
|
+
|
251
|
+
before do
|
252
|
+
require 'benchmark'
|
253
|
+
subject.start
|
254
|
+
servers.each { |server| send_beacon(:heartbeat, server) }
|
255
|
+
end
|
256
|
+
|
257
|
+
after do
|
258
|
+
subject.stop
|
259
|
+
end
|
171
260
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
it "removes a listing" do
|
181
|
-
instance.should_receive(:remove_listing_for).with(server)
|
182
|
-
instance.should_receive(:remove_expired_listings)
|
183
|
-
socket.send(payload, 0)
|
184
|
-
sleep 0.01
|
261
|
+
it "should perform lookups in constant time" do
|
262
|
+
print "\n\n"
|
263
|
+
Benchmark.bm(17) do |x|
|
264
|
+
x.report(" 1_000 lookups:") { 1_000.times { subject.lookup("PerformanceService#{rand(0..9)}") } }
|
265
|
+
x.report(" 10_000 lookups:") { 10_000.times { subject.lookup("PerformanceService#{rand(0..9)}") } }
|
266
|
+
x.report("100_000 lookups:") { 100_000.times { subject.lookup("PerformanceService#{rand(0..9)}") } }
|
267
|
+
end
|
185
268
|
end
|
186
269
|
end
|
187
270
|
end
|
@@ -67,7 +67,7 @@ describe Protobuf::Rpc::ServiceDispatcher do
|
|
67
67
|
|
68
68
|
context 'an object that responds to to_hash but is not a hash' do
|
69
69
|
let(:hashable) do
|
70
|
-
|
70
|
+
double('hashable', :to_hash => { :name => 'hashable' })
|
71
71
|
end
|
72
72
|
before { subject.callable_method.should_receive(:call) }
|
73
73
|
before { subject.service.stub(:response).and_return(hashable) }
|
@@ -78,7 +78,7 @@ describe Protobuf::Rpc::ServiceDispatcher do
|
|
78
78
|
|
79
79
|
context 'an object that responds to to_proto' do
|
80
80
|
let(:protoable) do
|
81
|
-
|
81
|
+
double('protoable', :to_proto => Test::Resource.new(:name => 'protoable'))
|
82
82
|
end
|
83
83
|
before { subject.callable_method.should_receive(:call) }
|
84
84
|
before { subject.service.stub(:response).and_return(protoable) }
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
require 'active_support/core_ext/numeric/time'
|
4
|
+
|
5
|
+
describe ::Protobuf::Rpc::Stat do
|
6
|
+
|
7
|
+
before(:all) do
|
8
|
+
unless defined?(BarService)
|
9
|
+
class BarService < ::Struct.new(:method_name); end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'server mode' do
|
14
|
+
it 'describes a server response to a client' do
|
15
|
+
::Timecop.freeze(10.minutes.ago) do
|
16
|
+
stats = ::Protobuf::Rpc::Stat.new(:SERVER)
|
17
|
+
stats.client = 'myserver1'
|
18
|
+
stats.dispatcher = double('dispatcher', :service => BarService.new(:find_bars))
|
19
|
+
stats.request_size = 43
|
20
|
+
stats.response_size = 1302
|
21
|
+
|
22
|
+
::Timecop.freeze(1.62.seconds.from_now) do
|
23
|
+
stats.stop
|
24
|
+
stats.to_s.should eq "[SRV] - myserver1 - #{stats.trace_id} - BarService#find_bars - 43B/1302B - 1.62s - #{::Time.now.iso8601}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when request is still running' do
|
30
|
+
it 'omits response size, duration, and timestamp' do
|
31
|
+
stats = ::Protobuf::Rpc::Stat.new(:SERVER)
|
32
|
+
stats.client = 'myserver1'
|
33
|
+
stats.dispatcher = double('dispatcher', :service => BarService.new(:find_bars))
|
34
|
+
stats.request_size = 43
|
35
|
+
stats.to_s.should eq "[SRV] - myserver1 - #{stats.trace_id} - BarService#find_bars - 43B/-"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'client mode' do
|
41
|
+
it 'describes a client request to a server' do
|
42
|
+
::Timecop.freeze(10.minutes.ago) do
|
43
|
+
stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
|
44
|
+
stats.server = ['30000', 'myserver1.myhost.com']
|
45
|
+
stats.service = 'Foo::BarService'
|
46
|
+
stats.method_name = 'find_bars'
|
47
|
+
stats.request_size = 37
|
48
|
+
stats.response_size = 12345
|
49
|
+
|
50
|
+
::Timecop.freeze(0.832.seconds.from_now) do
|
51
|
+
stats.stop
|
52
|
+
stats.to_s.should eq "[CLT] - myserver1.myhost.com:30000 - #{stats.trace_id} - Foo::BarService#find_bars - 37B/12345B - 0.832s - #{::Time.now.iso8601}"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when request is still running' do
|
59
|
+
it 'omits response size, duration, and timestamp' do
|
60
|
+
stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
|
61
|
+
stats.server = ['30000', 'myserver1.myhost.com']
|
62
|
+
stats.service = 'Foo::BarService'
|
63
|
+
stats.method_name = 'find_bars'
|
64
|
+
stats.request_size = 37
|
65
|
+
stats.to_s.should eq "[CLT] - myserver1.myhost.com:30000 - #{stats.trace_id} - Foo::BarService#find_bars - 37B/-"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: protobuf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.8.
|
4
|
+
version: 2.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- BJ Neilsen
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-08-
|
13
|
+
date: 2013-08-28 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -111,7 +111,7 @@ dependencies:
|
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: '0'
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
|
-
name:
|
114
|
+
name: rspec
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
116
116
|
requirements:
|
117
117
|
- - '>='
|
@@ -125,7 +125,7 @@ dependencies:
|
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
127
|
- !ruby/object:Gem::Dependency
|
128
|
-
name:
|
128
|
+
name: simplecov
|
129
129
|
requirement: !ruby/object:Gem::Requirement
|
130
130
|
requirements:
|
131
131
|
- - '>='
|
@@ -139,7 +139,7 @@ dependencies:
|
|
139
139
|
- !ruby/object:Gem::Version
|
140
140
|
version: '0'
|
141
141
|
- !ruby/object:Gem::Dependency
|
142
|
-
name:
|
142
|
+
name: yard
|
143
143
|
requirement: !ruby/object:Gem::Requirement
|
144
144
|
requirements:
|
145
145
|
- - '>='
|
@@ -153,7 +153,7 @@ dependencies:
|
|
153
153
|
- !ruby/object:Gem::Version
|
154
154
|
version: '0'
|
155
155
|
- !ruby/object:Gem::Dependency
|
156
|
-
name:
|
156
|
+
name: timecop
|
157
157
|
requirement: !ruby/object:Gem::Requirement
|
158
158
|
requirements:
|
159
159
|
- - '>='
|
@@ -317,6 +317,7 @@ files:
|
|
317
317
|
- spec/lib/protobuf/rpc/service_dispatcher_spec.rb
|
318
318
|
- spec/lib/protobuf/rpc/service_filters_spec.rb
|
319
319
|
- spec/lib/protobuf/rpc/service_spec.rb
|
320
|
+
- spec/lib/protobuf/rpc/stat_spec.rb
|
320
321
|
- spec/lib/protobuf_spec.rb
|
321
322
|
- spec/spec_helper.rb
|
322
323
|
- spec/support/all.rb
|
@@ -409,6 +410,7 @@ test_files:
|
|
409
410
|
- spec/lib/protobuf/rpc/service_dispatcher_spec.rb
|
410
411
|
- spec/lib/protobuf/rpc/service_filters_spec.rb
|
411
412
|
- spec/lib/protobuf/rpc/service_spec.rb
|
413
|
+
- spec/lib/protobuf/rpc/stat_spec.rb
|
412
414
|
- spec/lib/protobuf_spec.rb
|
413
415
|
- spec/spec_helper.rb
|
414
416
|
- spec/support/all.rb
|