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