protobuf 2.8.0 → 2.8.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.
- 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
|