prepor-protobuf 3.5.0

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.
Files changed (182) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rubocop.yml +51 -0
  4. data/.rubocop_todo.yml +89 -0
  5. data/.travis.yml +25 -0
  6. data/.yardopts +5 -0
  7. data/CHANGES.md +256 -0
  8. data/CONTRIBUTING.md +16 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +33 -0
  12. data/Rakefile +64 -0
  13. data/bin/protoc-gen-ruby +16 -0
  14. data/bin/rpc_server +5 -0
  15. data/install-protobuf.sh +28 -0
  16. data/lib/protobuf.rb +100 -0
  17. data/lib/protobuf/cli.rb +242 -0
  18. data/lib/protobuf/code_generator.rb +44 -0
  19. data/lib/protobuf/decoder.rb +73 -0
  20. data/lib/protobuf/deprecation.rb +112 -0
  21. data/lib/protobuf/descriptors.rb +3 -0
  22. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +48 -0
  23. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +251 -0
  24. data/lib/protobuf/encoder.rb +67 -0
  25. data/lib/protobuf/enum.rb +303 -0
  26. data/lib/protobuf/exceptions.rb +9 -0
  27. data/lib/protobuf/field.rb +74 -0
  28. data/lib/protobuf/field/base_field.rb +267 -0
  29. data/lib/protobuf/field/bool_field.rb +59 -0
  30. data/lib/protobuf/field/bytes_field.rb +82 -0
  31. data/lib/protobuf/field/double_field.rb +25 -0
  32. data/lib/protobuf/field/enum_field.rb +68 -0
  33. data/lib/protobuf/field/field_array.rb +87 -0
  34. data/lib/protobuf/field/fixed32_field.rb +25 -0
  35. data/lib/protobuf/field/fixed64_field.rb +28 -0
  36. data/lib/protobuf/field/float_field.rb +41 -0
  37. data/lib/protobuf/field/int32_field.rb +21 -0
  38. data/lib/protobuf/field/int64_field.rb +21 -0
  39. data/lib/protobuf/field/integer_field.rb +23 -0
  40. data/lib/protobuf/field/message_field.rb +65 -0
  41. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  42. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  43. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  44. data/lib/protobuf/field/sint32_field.rb +21 -0
  45. data/lib/protobuf/field/sint64_field.rb +21 -0
  46. data/lib/protobuf/field/string_field.rb +34 -0
  47. data/lib/protobuf/field/uint32_field.rb +21 -0
  48. data/lib/protobuf/field/uint64_field.rb +21 -0
  49. data/lib/protobuf/field/varint_field.rb +73 -0
  50. data/lib/protobuf/generators/base.rb +70 -0
  51. data/lib/protobuf/generators/enum_generator.rb +41 -0
  52. data/lib/protobuf/generators/extension_generator.rb +27 -0
  53. data/lib/protobuf/generators/field_generator.rb +131 -0
  54. data/lib/protobuf/generators/file_generator.rb +135 -0
  55. data/lib/protobuf/generators/group_generator.rb +112 -0
  56. data/lib/protobuf/generators/message_generator.rb +98 -0
  57. data/lib/protobuf/generators/printable.rb +160 -0
  58. data/lib/protobuf/generators/service_generator.rb +26 -0
  59. data/lib/protobuf/lifecycle.rb +33 -0
  60. data/lib/protobuf/logging.rb +39 -0
  61. data/lib/protobuf/message.rb +193 -0
  62. data/lib/protobuf/message/fields.rb +133 -0
  63. data/lib/protobuf/message/serialization.rb +89 -0
  64. data/lib/protobuf/optionable.rb +23 -0
  65. data/lib/protobuf/rpc/buffer.rb +77 -0
  66. data/lib/protobuf/rpc/client.rb +168 -0
  67. data/lib/protobuf/rpc/connector.rb +19 -0
  68. data/lib/protobuf/rpc/connectors/base.rb +55 -0
  69. data/lib/protobuf/rpc/connectors/common.rb +176 -0
  70. data/lib/protobuf/rpc/connectors/socket.rb +73 -0
  71. data/lib/protobuf/rpc/connectors/zmq.rb +322 -0
  72. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
  73. data/lib/protobuf/rpc/env.rb +58 -0
  74. data/lib/protobuf/rpc/error.rb +28 -0
  75. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  76. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  77. data/lib/protobuf/rpc/middleware.rb +25 -0
  78. data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
  79. data/lib/protobuf/rpc/middleware/logger.rb +91 -0
  80. data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
  81. data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
  82. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  83. data/lib/protobuf/rpc/rpc.pb.rb +55 -0
  84. data/lib/protobuf/rpc/server.rb +39 -0
  85. data/lib/protobuf/rpc/servers/socket/server.rb +123 -0
  86. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  87. data/lib/protobuf/rpc/servers/socket_runner.rb +40 -0
  88. data/lib/protobuf/rpc/servers/zmq/broker.rb +193 -0
  89. data/lib/protobuf/rpc/servers/zmq/server.rb +320 -0
  90. data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
  91. data/lib/protobuf/rpc/servers/zmq/worker.rb +104 -0
  92. data/lib/protobuf/rpc/servers/zmq_runner.rb +62 -0
  93. data/lib/protobuf/rpc/service.rb +179 -0
  94. data/lib/protobuf/rpc/service_directory.rb +253 -0
  95. data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
  96. data/lib/protobuf/rpc/service_filters.rb +272 -0
  97. data/lib/protobuf/rpc/stat.rb +97 -0
  98. data/lib/protobuf/socket.rb +21 -0
  99. data/lib/protobuf/tasks.rb +1 -0
  100. data/lib/protobuf/tasks/compile.rake +61 -0
  101. data/lib/protobuf/version.rb +3 -0
  102. data/lib/protobuf/wire_type.rb +10 -0
  103. data/lib/protobuf/zmq.rb +21 -0
  104. data/proto/dynamic_discovery.proto +44 -0
  105. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  106. data/proto/google/protobuf/descriptor.proto +620 -0
  107. data/proto/rpc.proto +62 -0
  108. data/protobuf.gemspec +51 -0
  109. data/spec/benchmark/tasks.rb +139 -0
  110. data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
  111. data/spec/data/data.bin +3 -0
  112. data/spec/data/types.bin +0 -0
  113. data/spec/encoding/all_types_spec.rb +105 -0
  114. data/spec/encoding/extreme_values_spec.rb +0 -0
  115. data/spec/functional/class_inheritance_spec.rb +52 -0
  116. data/spec/functional/socket_server_spec.rb +59 -0
  117. data/spec/functional/zmq_server_spec.rb +105 -0
  118. data/spec/lib/protobuf/cli_spec.rb +273 -0
  119. data/spec/lib/protobuf/code_generator_spec.rb +60 -0
  120. data/spec/lib/protobuf/enum_spec.rb +265 -0
  121. data/spec/lib/protobuf/field/bool_field_spec.rb +51 -0
  122. data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
  123. data/spec/lib/protobuf/field/float_field_spec.rb +55 -0
  124. data/spec/lib/protobuf/field/int32_field_spec.rb +89 -0
  125. data/spec/lib/protobuf/field/string_field_spec.rb +45 -0
  126. data/spec/lib/protobuf/field_spec.rb +191 -0
  127. data/spec/lib/protobuf/generators/base_spec.rb +84 -0
  128. data/spec/lib/protobuf/generators/enum_generator_spec.rb +73 -0
  129. data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
  130. data/spec/lib/protobuf/generators/field_generator_spec.rb +102 -0
  131. data/spec/lib/protobuf/generators/file_generator_spec.rb +32 -0
  132. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  133. data/spec/lib/protobuf/generators/service_generator_spec.rb +46 -0
  134. data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
  135. data/spec/lib/protobuf/message_spec.rb +526 -0
  136. data/spec/lib/protobuf/optionable_spec.rb +46 -0
  137. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  138. data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
  139. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
  140. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
  141. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +36 -0
  142. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +117 -0
  143. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  144. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  145. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  146. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
  147. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  148. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
  149. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  150. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  151. data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
  152. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
  153. data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
  154. data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
  155. data/spec/lib/protobuf/rpc/stat_spec.rb +68 -0
  156. data/spec/lib/protobuf_spec.rb +98 -0
  157. data/spec/spec_helper.rb +44 -0
  158. data/spec/support/all.rb +6 -0
  159. data/spec/support/packed_field.rb +22 -0
  160. data/spec/support/server.rb +64 -0
  161. data/spec/support/test/all_types.data.bin +0 -0
  162. data/spec/support/test/all_types.data.txt +119 -0
  163. data/spec/support/test/defaults.pb.rb +27 -0
  164. data/spec/support/test/defaults.proto +9 -0
  165. data/spec/support/test/enum.pb.rb +55 -0
  166. data/spec/support/test/enum.proto +34 -0
  167. data/spec/support/test/extended.pb.rb +18 -0
  168. data/spec/support/test/extended.proto +10 -0
  169. data/spec/support/test/extreme_values.data.bin +0 -0
  170. data/spec/support/test/google_unittest.pb.rb +537 -0
  171. data/spec/support/test/google_unittest.proto +713 -0
  172. data/spec/support/test/google_unittest_import.pb.rb +39 -0
  173. data/spec/support/test/google_unittest_import.proto +64 -0
  174. data/spec/support/test/google_unittest_import_public.pb.rb +10 -0
  175. data/spec/support/test/google_unittest_import_public.proto +38 -0
  176. data/spec/support/test/multi_field_extensions.pb.rb +58 -0
  177. data/spec/support/test/multi_field_extensions.proto +33 -0
  178. data/spec/support/test/resource.pb.rb +119 -0
  179. data/spec/support/test/resource.proto +94 -0
  180. data/spec/support/test/resource_service.rb +23 -0
  181. data/spec/support/test_app_file.rb +2 -0
  182. metadata +502 -0
@@ -0,0 +1,320 @@
1
+ require 'protobuf/rpc/servers/zmq/util'
2
+ require 'protobuf/rpc/servers/zmq/worker'
3
+ require 'protobuf/rpc/servers/zmq/broker'
4
+ require 'protobuf/rpc/dynamic_discovery.pb'
5
+ require 'securerandom'
6
+ require 'thread'
7
+
8
+ module Protobuf
9
+ module Rpc
10
+ module Zmq
11
+ class Server
12
+ include ::Protobuf::Rpc::Zmq::Util
13
+
14
+ DEFAULT_OPTIONS = {
15
+ :beacon_interval => 5,
16
+ :broadcast_beacons => false,
17
+ :broadcast_busy => false,
18
+ :zmq_inproc => true,
19
+ }
20
+
21
+ attr_accessor :options, :workers
22
+ attr_reader :zmq_context
23
+
24
+ def initialize(options)
25
+ @options = DEFAULT_OPTIONS.merge(options)
26
+ @workers = []
27
+
28
+ init_zmq_context
29
+ init_beacon_socket if broadcast_beacons?
30
+ init_shutdown_pipe
31
+ rescue
32
+ teardown
33
+ raise
34
+ end
35
+
36
+ def add_worker
37
+ @total_workers = total_workers + 1
38
+ end
39
+
40
+ def all_workers_busy?
41
+ workers.all? { |thread| !!thread[:busy] }
42
+ end
43
+
44
+ def backend_port
45
+ options[:worker_port] || frontend_port + 1
46
+ end
47
+
48
+ def backend_uri
49
+ if inproc?
50
+ "inproc://#{backend_ip}:#{backend_port}"
51
+ else
52
+ "tcp://#{backend_ip}:#{backend_port}"
53
+ end
54
+ end
55
+
56
+ def beacon_interval
57
+ [options[:beacon_interval].to_i, 1].max
58
+ end
59
+
60
+ def beacon_ip
61
+ "255.255.255.255"
62
+ end
63
+
64
+ def beacon_port
65
+ @beacon_port ||= options.fetch(
66
+ :beacon_port,
67
+ ::Protobuf::Rpc::ServiceDirectory.port,
68
+ ).to_i
69
+ end
70
+
71
+ def beacon_uri
72
+ "udp://#{beacon_ip}:#{beacon_port}"
73
+ end
74
+
75
+ def broadcast_beacons?
76
+ !brokerless? && options[:broadcast_beacons]
77
+ end
78
+
79
+ def broadcast_busy?
80
+ broadcast_beacons? && options[:broadcast_busy]
81
+ end
82
+
83
+ def broadcast_flatline
84
+ flatline = ::Protobuf::Rpc::DynamicDiscovery::Beacon.new(
85
+ :beacon_type => ::Protobuf::Rpc::DynamicDiscovery::BeaconType::FLATLINE,
86
+ :server => to_proto,
87
+ )
88
+
89
+ @beacon_socket.send(flatline.encode, 0)
90
+ end
91
+
92
+ def broadcast_heartbeat
93
+ @last_beacon = Time.now.to_i
94
+
95
+ heartbeat = ::Protobuf::Rpc::DynamicDiscovery::Beacon.new(
96
+ :beacon_type => ::Protobuf::Rpc::DynamicDiscovery::BeaconType::HEARTBEAT,
97
+ :server => to_proto,
98
+ )
99
+
100
+ @beacon_socket.send(heartbeat.encode, 0)
101
+
102
+ logger.debug { sign_message("sent heartbeat to #{beacon_uri}") }
103
+ end
104
+
105
+ def broadcast_heartbeat?
106
+ Time.now.to_i >= next_beacon && broadcast_beacons?
107
+ end
108
+
109
+ def brokerless?
110
+ !!options[:workers_only]
111
+ end
112
+
113
+ def busy_worker_count
114
+ workers.count { |thread| !!thread[:busy] }
115
+ end
116
+
117
+ def frontend_ip
118
+ @frontend_ip ||= resolve_ip(options[:host])
119
+ end
120
+ alias_method :backend_ip, :frontend_ip
121
+
122
+ def frontend_port
123
+ options[:port]
124
+ end
125
+
126
+ def frontend_uri
127
+ "tcp://#{frontend_ip}:#{frontend_port}"
128
+ end
129
+
130
+ def inproc?
131
+ !!options[:zmq_inproc]
132
+ end
133
+
134
+ def maintenance_timeout
135
+ next_maintenance - Time.now.to_i
136
+ end
137
+
138
+ def next_maintenance
139
+ cycles = [next_reaping]
140
+ cycles << next_beacon if broadcast_beacons?
141
+
142
+ cycles.min
143
+ end
144
+
145
+ def minimum_timeout
146
+ 0.1
147
+ end
148
+
149
+ def next_beacon
150
+ if @last_beacon.nil?
151
+ 0
152
+ else
153
+ @last_beacon + beacon_interval
154
+ end
155
+ end
156
+
157
+ def next_reaping
158
+ if @last_reaping.nil?
159
+ 0
160
+ else
161
+ @last_reaping + reaping_interval
162
+ end
163
+ end
164
+
165
+ def reap_dead_workers
166
+ @last_reaping = Time.now.to_i
167
+
168
+ @workers.keep_if do |worker|
169
+ worker.alive? || worker.join && false
170
+ end
171
+ end
172
+
173
+ def reap_dead_workers?
174
+ Time.now.to_i >= next_reaping
175
+ end
176
+
177
+ def reaping_interval
178
+ 5
179
+ end
180
+
181
+ def run
182
+ @running = true
183
+ yield if block_given? # runs on startup
184
+ wait_for_shutdown_signal
185
+ broadcast_flatline if broadcast_beacons?
186
+ Thread.pass until reap_dead_workers.empty?
187
+ @broker_thread.join unless brokerless?
188
+ ensure
189
+ @running = false
190
+ teardown
191
+ end
192
+
193
+ def running?
194
+ !!@running
195
+ end
196
+
197
+ def start_missing_workers
198
+ missing_workers = total_workers - @workers.size
199
+
200
+ if missing_workers > 0
201
+ missing_workers.times { start_worker }
202
+ logger.debug { sign_message("#{total_workers} workers started") }
203
+ end
204
+ end
205
+
206
+ def stop
207
+ @running = false
208
+ @shutdown_w.write('.')
209
+ end
210
+
211
+ def teardown
212
+ @shutdown_r.try(:close)
213
+ @shutdown_w.try(:close)
214
+ @beacon_socket.try(:close)
215
+ @zmq_context.try(:terminate)
216
+ @last_reaping = @last_beacon = @timeout = nil
217
+ end
218
+
219
+ def timeout
220
+ if @timeout.nil?
221
+ @timeout = 0
222
+ else
223
+ @timeout = [minimum_timeout, maintenance_timeout].max
224
+ end
225
+ end
226
+
227
+ def total_workers
228
+ @total_workers ||= [@options[:threads].to_i, 1].max
229
+ end
230
+
231
+ def to_proto
232
+ @proto ||= ::Protobuf::Rpc::DynamicDiscovery::Server.new(
233
+ :uuid => uuid,
234
+ :address => frontend_ip,
235
+ :port => frontend_port.to_s,
236
+ :ttl => (beacon_interval * 1.5).ceil,
237
+ :services => ::Protobuf::Rpc::Service.implemented_services,
238
+ )
239
+ end
240
+
241
+ def uuid
242
+ @uuid ||= SecureRandom.uuid
243
+ end
244
+
245
+ def wait_for_shutdown_signal
246
+ loop do
247
+ break if IO.select([@shutdown_r], nil, nil, timeout)
248
+
249
+ start_broker unless brokerless?
250
+ reap_dead_workers if reap_dead_workers?
251
+ start_missing_workers
252
+
253
+ next unless broadcast_heartbeat?
254
+
255
+ if broadcast_busy? && all_workers_busy?
256
+ broadcast_flatline
257
+ else
258
+ broadcast_heartbeat
259
+ end
260
+ end
261
+ end
262
+
263
+ private
264
+
265
+ def init_beacon_socket
266
+ @beacon_socket = UDPSocket.new
267
+ @beacon_socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_BROADCAST, true)
268
+ @beacon_socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, true)
269
+
270
+ if defined?(::Socket::SO_REUSEPORT)
271
+ @beacon_socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEPORT, true)
272
+ end
273
+
274
+ @beacon_socket.bind(frontend_ip, beacon_port)
275
+ @beacon_socket.connect(beacon_ip, beacon_port)
276
+ end
277
+
278
+ def init_shutdown_pipe
279
+ @shutdown_r, @shutdown_w = IO.pipe
280
+ end
281
+
282
+ def init_zmq_context
283
+ @zmq_context = ZMQ::Context.new
284
+ end
285
+
286
+ def start_broker
287
+ return if @broker && @broker.running? && !@broker_thread.stop?
288
+ if @broker && !@broker.running?
289
+ broadcast_flatline if broadcast_busy?
290
+ @broker_thread.join if @broker_thread
291
+ init_zmq_context # need a new context to restart the broker
292
+ end
293
+
294
+ @broker = ::Protobuf::Rpc::Zmq::Broker.new(self)
295
+ @broker_thread = Thread.new(@broker) do |broker|
296
+ begin
297
+ broker.run
298
+ rescue => e
299
+ message = "Broker failed: #{e.inspect}\n #{e.backtrace.join($INPUT_RECORD_SEPARATOR)}"
300
+ $stderr.puts(message)
301
+ logger.error { message }
302
+ end
303
+ end
304
+ end
305
+
306
+ def start_worker
307
+ @workers << Thread.new(self, @broker) do |server, broker|
308
+ begin
309
+ ::Protobuf::Rpc::Zmq::Worker.new(server, broker).run
310
+ rescue => e
311
+ message = "Worker failed: #{e.inspect}\n #{e.backtrace.join($INPUT_RECORD_SEPARATOR)}"
312
+ $stderr.puts(message)
313
+ logger.error { message }
314
+ end
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,48 @@
1
+ require 'resolv'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ module Zmq
6
+
7
+ ADDRESS_MATCH = /\A\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/.freeze
8
+ WORKER_READY_MESSAGE = "\1"
9
+ CHECK_AVAILABLE_MESSAGE = "\3"
10
+ NO_WORKERS_AVAILABLE = "\4"
11
+ WORKERS_AVAILABLE = "\5"
12
+ EMPTY_STRING = ""
13
+
14
+ module Util
15
+ include ::Protobuf::Logging
16
+
17
+ def self.included(base)
18
+ base.extend(::Protobuf::Rpc::Zmq::Util)
19
+ end
20
+
21
+ def zmq_error_check(return_code, source = nil)
22
+ return if ::ZMQ::Util.resultcode_ok?(return_code)
23
+
24
+ fail <<-ERROR
25
+ Last ZMQ API call #{source ? "to #{source}" : ''} failed with "#{::ZMQ::Util.error_string}".
26
+
27
+ #{caller(1).join($INPUT_RECORD_SEPARATOR)}
28
+ ERROR
29
+ end
30
+
31
+ def log_signature
32
+ unless @_log_signature
33
+ name = (self.class == Class ? self.name : self.class.name)
34
+ @_log_signature = "[server-#{name}-#{object_id}]"
35
+ end
36
+
37
+ @_log_signature
38
+ end
39
+
40
+ def resolve_ip(hostname)
41
+ ::Resolv.getaddresses(hostname).find do |address|
42
+ address =~ ADDRESS_MATCH
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,104 @@
1
+ require 'protobuf/rpc/server'
2
+ require 'protobuf/rpc/servers/zmq/util'
3
+ require 'thread'
4
+
5
+ module Protobuf
6
+ module Rpc
7
+ module Zmq
8
+ class Worker
9
+ include ::Protobuf::Rpc::Server
10
+ include ::Protobuf::Rpc::Zmq::Util
11
+
12
+ ##
13
+ # Constructor
14
+ #
15
+ def initialize(server, broker)
16
+ @server = server
17
+ @broker = broker
18
+
19
+ init_zmq_context
20
+ init_backend_socket
21
+ rescue
22
+ teardown
23
+ raise
24
+ end
25
+
26
+ ##
27
+ # Instance Methods
28
+ #
29
+ def process_request
30
+ client_address, _, data = read_from_backend
31
+ return unless data
32
+
33
+ gc_pause do
34
+ encoded_response = handle_request(data)
35
+ write_to_backend([client_address, ::Protobuf::Rpc::Zmq::EMPTY_STRING, encoded_response])
36
+ end
37
+ end
38
+
39
+ def run
40
+ poller = ::ZMQ::Poller.new
41
+ poller.register_readable(@backend_socket)
42
+ poller.register_readable(@shutdown_socket)
43
+
44
+ # Send request to broker telling it we are ready
45
+ write_to_backend([::Protobuf::Rpc::Zmq::WORKER_READY_MESSAGE])
46
+
47
+ loop do
48
+ rc = poller.poll(500)
49
+
50
+ if rc == 0 && !running?
51
+ break # The server was shutdown and no requests are pending
52
+ elsif rc == -1
53
+ break # Something went wrong
54
+ elsif rc > 0
55
+ ::Thread.current[:busy] = true
56
+ process_request
57
+ ::Thread.current[:busy] = false
58
+ end
59
+ end
60
+ ensure
61
+ teardown
62
+ end
63
+
64
+ def running?
65
+ @broker.running? && @server.running?
66
+ end
67
+
68
+ private
69
+
70
+ def init_zmq_context
71
+ if inproc?
72
+ @zmq_context = @server.zmq_context
73
+ else
74
+ @zmq_context = ZMQ::Context.new
75
+ end
76
+ end
77
+
78
+ def init_backend_socket
79
+ @backend_socket = @zmq_context.socket(ZMQ::REQ)
80
+ zmq_error_check(@backend_socket.connect(@server.backend_uri))
81
+ end
82
+
83
+ def inproc?
84
+ !!@server.try(:inproc?)
85
+ end
86
+
87
+ def read_from_backend
88
+ frames = []
89
+ zmq_error_check(@backend_socket.recv_strings(frames))
90
+ frames
91
+ end
92
+
93
+ def teardown
94
+ @backend_socket.try(:close)
95
+ @zmq_context.try(:terminate) unless inproc?
96
+ end
97
+
98
+ def write_to_backend(frames)
99
+ zmq_error_check(@backend_socket.send_strings(frames))
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end