grpc 1.60.0.pre1-aarch64-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/etc/roots.pem +4337 -0
  3. data/grpc_c.32-msvcrt.ruby +0 -0
  4. data/grpc_c.64-msvcrt.ruby +0 -0
  5. data/grpc_c.64-ucrt.ruby +0 -0
  6. data/src/ruby/bin/math_client.rb +140 -0
  7. data/src/ruby/bin/math_pb.rb +40 -0
  8. data/src/ruby/bin/math_server.rb +191 -0
  9. data/src/ruby/bin/math_services_pb.rb +51 -0
  10. data/src/ruby/bin/noproto_client.rb +93 -0
  11. data/src/ruby/bin/noproto_server.rb +97 -0
  12. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.clang +2 -0
  13. data/src/ruby/ext/grpc/ext-export-truffleruby-with-ruby-abi-version.gcc +7 -0
  14. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.clang +2 -0
  15. data/src/ruby/ext/grpc/ext-export-with-ruby-abi-version.gcc +7 -0
  16. data/src/ruby/ext/grpc/ext-export.clang +1 -0
  17. data/src/ruby/ext/grpc/ext-export.gcc +6 -0
  18. data/src/ruby/ext/grpc/extconf.rb +270 -0
  19. data/src/ruby/ext/grpc/rb_byte_buffer.c +65 -0
  20. data/src/ruby/ext/grpc/rb_byte_buffer.h +35 -0
  21. data/src/ruby/ext/grpc/rb_call.c +1075 -0
  22. data/src/ruby/ext/grpc/rb_call.h +57 -0
  23. data/src/ruby/ext/grpc/rb_call_credentials.c +340 -0
  24. data/src/ruby/ext/grpc/rb_call_credentials.h +31 -0
  25. data/src/ruby/ext/grpc/rb_channel.c +875 -0
  26. data/src/ruby/ext/grpc/rb_channel.h +35 -0
  27. data/src/ruby/ext/grpc/rb_channel_args.c +172 -0
  28. data/src/ruby/ext/grpc/rb_channel_args.h +42 -0
  29. data/src/ruby/ext/grpc/rb_channel_credentials.c +285 -0
  30. data/src/ruby/ext/grpc/rb_channel_credentials.h +37 -0
  31. data/src/ruby/ext/grpc/rb_completion_queue.c +101 -0
  32. data/src/ruby/ext/grpc/rb_completion_queue.h +36 -0
  33. data/src/ruby/ext/grpc/rb_compression_options.c +470 -0
  34. data/src/ruby/ext/grpc/rb_compression_options.h +29 -0
  35. data/src/ruby/ext/grpc/rb_enable_cpp.cc +22 -0
  36. data/src/ruby/ext/grpc/rb_event_thread.c +161 -0
  37. data/src/ruby/ext/grpc/rb_event_thread.h +22 -0
  38. data/src/ruby/ext/grpc/rb_grpc.c +496 -0
  39. data/src/ruby/ext/grpc/rb_grpc.h +83 -0
  40. data/src/ruby/ext/grpc/rb_grpc_imports.generated.c +603 -0
  41. data/src/ruby/ext/grpc/rb_grpc_imports.generated.h +910 -0
  42. data/src/ruby/ext/grpc/rb_loader.c +61 -0
  43. data/src/ruby/ext/grpc/rb_loader.h +25 -0
  44. data/src/ruby/ext/grpc/rb_server.c +405 -0
  45. data/src/ruby/ext/grpc/rb_server.h +32 -0
  46. data/src/ruby/ext/grpc/rb_server_credentials.c +258 -0
  47. data/src/ruby/ext/grpc/rb_server_credentials.h +37 -0
  48. data/src/ruby/ext/grpc/rb_xds_channel_credentials.c +217 -0
  49. data/src/ruby/ext/grpc/rb_xds_channel_credentials.h +37 -0
  50. data/src/ruby/ext/grpc/rb_xds_server_credentials.c +169 -0
  51. data/src/ruby/ext/grpc/rb_xds_server_credentials.h +37 -0
  52. data/src/ruby/lib/grpc/2.7/grpc_c.so +0 -0
  53. data/src/ruby/lib/grpc/3.0/grpc_c.so +0 -0
  54. data/src/ruby/lib/grpc/3.1/grpc_c.so +0 -0
  55. data/src/ruby/lib/grpc/3.2/grpc_c.so +0 -0
  56. data/src/ruby/lib/grpc/core/status_codes.rb +135 -0
  57. data/src/ruby/lib/grpc/core/time_consts.rb +56 -0
  58. data/src/ruby/lib/grpc/errors.rb +277 -0
  59. data/src/ruby/lib/grpc/generic/active_call.rb +670 -0
  60. data/src/ruby/lib/grpc/generic/bidi_call.rb +237 -0
  61. data/src/ruby/lib/grpc/generic/client_stub.rb +503 -0
  62. data/src/ruby/lib/grpc/generic/interceptor_registry.rb +53 -0
  63. data/src/ruby/lib/grpc/generic/interceptors.rb +186 -0
  64. data/src/ruby/lib/grpc/generic/rpc_desc.rb +204 -0
  65. data/src/ruby/lib/grpc/generic/rpc_server.rb +551 -0
  66. data/src/ruby/lib/grpc/generic/service.rb +211 -0
  67. data/src/ruby/lib/grpc/google_rpc_status_utils.rb +40 -0
  68. data/src/ruby/lib/grpc/grpc.rb +24 -0
  69. data/src/ruby/lib/grpc/logconfig.rb +44 -0
  70. data/src/ruby/lib/grpc/notifier.rb +45 -0
  71. data/src/ruby/lib/grpc/structs.rb +15 -0
  72. data/src/ruby/lib/grpc/version.rb +18 -0
  73. data/src/ruby/lib/grpc.rb +37 -0
  74. data/src/ruby/pb/README.md +42 -0
  75. data/src/ruby/pb/generate_proto_ruby.sh +46 -0
  76. data/src/ruby/pb/grpc/health/checker.rb +75 -0
  77. data/src/ruby/pb/grpc/health/v1/health_pb.rb +42 -0
  78. data/src/ruby/pb/grpc/health/v1/health_services_pb.rb +62 -0
  79. data/src/ruby/pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb +44 -0
  80. data/src/ruby/pb/grpc/testing/metrics_pb.rb +28 -0
  81. data/src/ruby/pb/grpc/testing/metrics_services_pb.rb +49 -0
  82. data/src/ruby/pb/src/proto/grpc/testing/empty_pb.rb +38 -0
  83. data/src/ruby/pb/src/proto/grpc/testing/messages_pb.rb +71 -0
  84. data/src/ruby/pb/src/proto/grpc/testing/test_pb.rb +40 -0
  85. data/src/ruby/pb/src/proto/grpc/testing/test_services_pb.rb +174 -0
  86. data/src/ruby/pb/test/client.rb +785 -0
  87. data/src/ruby/pb/test/server.rb +252 -0
  88. data/src/ruby/pb/test/xds_client.rb +415 -0
  89. data/src/ruby/spec/call_credentials_spec.rb +42 -0
  90. data/src/ruby/spec/call_spec.rb +180 -0
  91. data/src/ruby/spec/channel_connection_spec.rb +126 -0
  92. data/src/ruby/spec/channel_credentials_spec.rb +124 -0
  93. data/src/ruby/spec/channel_spec.rb +207 -0
  94. data/src/ruby/spec/client_auth_spec.rb +152 -0
  95. data/src/ruby/spec/client_server_spec.rb +676 -0
  96. data/src/ruby/spec/compression_options_spec.rb +149 -0
  97. data/src/ruby/spec/debug_message_spec.rb +134 -0
  98. data/src/ruby/spec/error_sanity_spec.rb +49 -0
  99. data/src/ruby/spec/errors_spec.rb +142 -0
  100. data/src/ruby/spec/generic/active_call_spec.rb +692 -0
  101. data/src/ruby/spec/generic/client_interceptors_spec.rb +153 -0
  102. data/src/ruby/spec/generic/client_stub_spec.rb +1083 -0
  103. data/src/ruby/spec/generic/interceptor_registry_spec.rb +65 -0
  104. data/src/ruby/spec/generic/rpc_desc_spec.rb +374 -0
  105. data/src/ruby/spec/generic/rpc_server_pool_spec.rb +127 -0
  106. data/src/ruby/spec/generic/rpc_server_spec.rb +748 -0
  107. data/src/ruby/spec/generic/server_interceptors_spec.rb +218 -0
  108. data/src/ruby/spec/generic/service_spec.rb +263 -0
  109. data/src/ruby/spec/google_rpc_status_utils_spec.rb +282 -0
  110. data/src/ruby/spec/pb/codegen/grpc/testing/package_options.proto +28 -0
  111. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import.proto +22 -0
  112. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_import2.proto +23 -0
  113. data/src/ruby/spec/pb/codegen/grpc/testing/package_options_ruby_style.proto +41 -0
  114. data/src/ruby/spec/pb/codegen/grpc/testing/same_package_service_name.proto +27 -0
  115. data/src/ruby/spec/pb/codegen/grpc/testing/same_ruby_package_service_name.proto +29 -0
  116. data/src/ruby/spec/pb/codegen/package_option_spec.rb +98 -0
  117. data/src/ruby/spec/pb/duplicate/codegen_spec.rb +57 -0
  118. data/src/ruby/spec/pb/health/checker_spec.rb +236 -0
  119. data/src/ruby/spec/server_credentials_spec.rb +104 -0
  120. data/src/ruby/spec/server_spec.rb +231 -0
  121. data/src/ruby/spec/spec_helper.rb +61 -0
  122. data/src/ruby/spec/support/helpers.rb +107 -0
  123. data/src/ruby/spec/support/services.rb +160 -0
  124. data/src/ruby/spec/testdata/README +1 -0
  125. data/src/ruby/spec/testdata/ca.pem +20 -0
  126. data/src/ruby/spec/testdata/client.key +28 -0
  127. data/src/ruby/spec/testdata/client.pem +20 -0
  128. data/src/ruby/spec/testdata/server1.key +28 -0
  129. data/src/ruby/spec/testdata/server1.pem +22 -0
  130. data/src/ruby/spec/time_consts_spec.rb +74 -0
  131. data/src/ruby/spec/user_agent_spec.rb +74 -0
  132. metadata +405 -0
@@ -0,0 +1,551 @@
1
+ # Copyright 2015 gRPC authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative '../grpc'
16
+ require_relative 'active_call'
17
+ require_relative 'service'
18
+ require 'thread'
19
+
20
+ # GRPC contains the General RPC module.
21
+ module GRPC
22
+ # Pool is a simple thread pool.
23
+ class Pool
24
+ # Default keep alive period is 1s
25
+ DEFAULT_KEEP_ALIVE = 1
26
+
27
+ def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE)
28
+ fail 'pool size must be positive' unless size > 0
29
+ @jobs = Queue.new
30
+ @size = size
31
+ @stopped = false
32
+ @stop_mutex = Mutex.new # needs to be held when accessing @stopped
33
+ @stop_cond = ConditionVariable.new
34
+ @workers = []
35
+ @keep_alive = keep_alive
36
+
37
+ # Each worker thread has its own queue to push and pull jobs
38
+ # these queues are put into @ready_queues when that worker is idle
39
+ @ready_workers = Queue.new
40
+ end
41
+
42
+ # Returns the number of jobs waiting
43
+ def jobs_waiting
44
+ @jobs.size
45
+ end
46
+
47
+ def ready_for_work?
48
+ # Busy worker threads are either doing work, or have a single job
49
+ # waiting on them. Workers that are idle with no jobs waiting
50
+ # have their "queues" in @ready_workers
51
+ !@ready_workers.empty?
52
+ end
53
+
54
+ # Runs the given block on the queue with the provided args.
55
+ #
56
+ # @param args the args passed blk when it is called
57
+ # @param blk the block to call
58
+ def schedule(*args, &blk)
59
+ return if blk.nil?
60
+ @stop_mutex.synchronize do
61
+ if @stopped
62
+ GRPC.logger.warn('did not schedule job, already stopped')
63
+ return
64
+ end
65
+ GRPC.logger.info('schedule another job')
66
+ fail 'No worker threads available' if @ready_workers.empty?
67
+ worker_queue = @ready_workers.pop
68
+
69
+ fail 'worker already has a task waiting' unless worker_queue.empty?
70
+ worker_queue << [blk, args]
71
+ end
72
+ end
73
+
74
+ # Starts running the jobs in the thread pool.
75
+ def start
76
+ @stop_mutex.synchronize do
77
+ fail 'already stopped' if @stopped
78
+ end
79
+ until @workers.size == @size.to_i
80
+ new_worker_queue = Queue.new
81
+ @ready_workers << new_worker_queue
82
+ next_thread = Thread.new(new_worker_queue) do |jobs|
83
+ catch(:exit) do # allows { throw :exit } to kill a thread
84
+ loop_execute_jobs(jobs)
85
+ end
86
+ remove_current_thread
87
+ end
88
+ @workers << next_thread
89
+ end
90
+ end
91
+
92
+ # Stops the jobs in the pool
93
+ def stop
94
+ GRPC.logger.info('stopping, will wait for all the workers to exit')
95
+ @stop_mutex.synchronize do # wait @keep_alive seconds for workers to stop
96
+ @stopped = true
97
+ loop do
98
+ break unless ready_for_work?
99
+ worker_queue = @ready_workers.pop
100
+ worker_queue << [proc { throw :exit }, []]
101
+ end
102
+ @stop_cond.wait(@stop_mutex, @keep_alive) if @workers.size > 0
103
+ end
104
+ forcibly_stop_workers
105
+ GRPC.logger.info('stopped, all workers are shutdown')
106
+ end
107
+
108
+ protected
109
+
110
+ # Forcibly shutdown any threads that are still alive.
111
+ def forcibly_stop_workers
112
+ return unless @workers.size > 0
113
+ GRPC.logger.info("forcibly terminating #{@workers.size} worker(s)")
114
+ @workers.each do |t|
115
+ next unless t.alive?
116
+ begin
117
+ t.exit
118
+ rescue StandardError => e
119
+ GRPC.logger.warn('error while terminating a worker')
120
+ GRPC.logger.warn(e)
121
+ end
122
+ end
123
+ end
124
+
125
+ # removes the threads from workers, and signal when all the
126
+ # threads are complete.
127
+ def remove_current_thread
128
+ @stop_mutex.synchronize do
129
+ @workers.delete(Thread.current)
130
+ @stop_cond.signal if @workers.size.zero?
131
+ end
132
+ end
133
+
134
+ def loop_execute_jobs(worker_queue)
135
+ loop do
136
+ begin
137
+ blk, args = worker_queue.pop
138
+ blk.call(*args)
139
+ rescue StandardError, GRPC::Core::CallError => e
140
+ GRPC.logger.warn('Error in worker thread')
141
+ GRPC.logger.warn(e)
142
+ end
143
+ # there shouldn't be any work given to this thread while its busy
144
+ fail('received a task while busy') unless worker_queue.empty?
145
+ @stop_mutex.synchronize do
146
+ return if @stopped
147
+ @ready_workers << worker_queue
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ # RpcServer hosts a number of services and makes them available on the
154
+ # network.
155
+ class RpcServer
156
+ include Core::CallOps
157
+ include Core::TimeConsts
158
+ extend ::Forwardable
159
+
160
+ def_delegators :@server, :add_http2_port
161
+
162
+ # Default thread pool size is 30
163
+ DEFAULT_POOL_SIZE = 30
164
+
165
+ # Deprecated due to internal changes to the thread pool
166
+ DEFAULT_MAX_WAITING_REQUESTS = 20
167
+
168
+ # Default poll period is 1s
169
+ DEFAULT_POLL_PERIOD = 1
170
+
171
+ # Signal check period is 0.25s
172
+ SIGNAL_CHECK_PERIOD = 0.25
173
+
174
+ # setup_connect_md_proc is used by #initialize to validate the
175
+ # connect_md_proc.
176
+ def self.setup_connect_md_proc(a_proc)
177
+ return nil if a_proc.nil?
178
+ fail(TypeError, '!Proc') unless a_proc.is_a? Proc
179
+ a_proc
180
+ end
181
+
182
+ # Creates a new RpcServer.
183
+ #
184
+ # The RPC server is configured using keyword arguments.
185
+ #
186
+ # There are some specific keyword args used to configure the RpcServer
187
+ # instance.
188
+ #
189
+ # * pool_size: the size of the thread pool the server uses to run its
190
+ # threads. No more concurrent requests can be made than the size
191
+ # of the thread pool
192
+ #
193
+ # * max_waiting_requests: Deprecated due to internal changes to the thread
194
+ # pool. This is still an argument for compatibility but is ignored.
195
+ #
196
+ # * poll_period: The amount of time in seconds to wait for
197
+ # currently-serviced RPC's to finish before cancelling them when shutting
198
+ # down the server.
199
+ #
200
+ # * pool_keep_alive: The amount of time in seconds to wait
201
+ # for currently busy thread-pool threads to finish before
202
+ # forcing an abrupt exit to each thread.
203
+ #
204
+ # * connect_md_proc:
205
+ # when non-nil is a proc for determining metadata to send back the client
206
+ # on receiving an invocation req. The proc signature is:
207
+ # {key: val, ..} func(method_name, {key: val, ...})
208
+ #
209
+ # * server_args:
210
+ # A server arguments hash to be passed down to the underlying core server
211
+ #
212
+ # * interceptors:
213
+ # An array of GRPC::ServerInterceptor objects that will be used for
214
+ # intercepting server handlers to provide extra functionality.
215
+ # Interceptors are an EXPERIMENTAL API.
216
+ #
217
+ def initialize(pool_size: DEFAULT_POOL_SIZE,
218
+ max_waiting_requests: DEFAULT_MAX_WAITING_REQUESTS,
219
+ poll_period: DEFAULT_POLL_PERIOD,
220
+ pool_keep_alive: Pool::DEFAULT_KEEP_ALIVE,
221
+ connect_md_proc: nil,
222
+ server_args: {},
223
+ interceptors: [])
224
+ @connect_md_proc = RpcServer.setup_connect_md_proc(connect_md_proc)
225
+ @max_waiting_requests = max_waiting_requests
226
+ @poll_period = poll_period
227
+ @pool_size = pool_size
228
+ @pool = Pool.new(@pool_size, keep_alive: pool_keep_alive)
229
+ @run_cond = ConditionVariable.new
230
+ @run_mutex = Mutex.new
231
+ # running_state can take 4 values: :not_started, :running, :stopping, and
232
+ # :stopped. State transitions can only proceed in that order.
233
+ @running_state = :not_started
234
+ @server = Core::Server.new(server_args)
235
+ @interceptors = InterceptorRegistry.new(interceptors)
236
+ end
237
+
238
+ # stops a running server
239
+ #
240
+ # the call has no impact if the server is already stopped, otherwise
241
+ # server's current call loop is it's last.
242
+ def stop
243
+ # if called via run_till_terminated_or_interrupted,
244
+ # signal stop_server_thread and don't do anything
245
+ if @stop_server.nil? == false && @stop_server == false
246
+ @stop_server = true
247
+ @stop_server_cv.broadcast
248
+ return
249
+ end
250
+ @run_mutex.synchronize do
251
+ fail 'Cannot stop before starting' if @running_state == :not_started
252
+ return if @running_state != :running
253
+ transition_running_state(:stopping)
254
+ deadline = from_relative_time(@poll_period)
255
+ @server.shutdown_and_notify(deadline)
256
+ end
257
+ @pool.stop
258
+ end
259
+
260
+ def running_state
261
+ @run_mutex.synchronize do
262
+ return @running_state
263
+ end
264
+ end
265
+
266
+ # Can only be called while holding @run_mutex
267
+ def transition_running_state(target_state)
268
+ state_transitions = {
269
+ not_started: :running,
270
+ running: :stopping,
271
+ stopping: :stopped
272
+ }
273
+ if state_transitions[@running_state] == target_state
274
+ @running_state = target_state
275
+ else
276
+ fail "Bad server state transition: #{@running_state}->#{target_state}"
277
+ end
278
+ end
279
+
280
+ def running?
281
+ running_state == :running
282
+ end
283
+
284
+ def stopped?
285
+ running_state == :stopped
286
+ end
287
+
288
+ # Is called from other threads to wait for #run to start up the server.
289
+ #
290
+ # If run has not been called, this returns immediately.
291
+ #
292
+ # @param timeout [Numeric] number of seconds to wait
293
+ # @return [true, false] true if the server is running, false otherwise
294
+ def wait_till_running(timeout = nil)
295
+ @run_mutex.synchronize do
296
+ @run_cond.wait(@run_mutex, timeout) if @running_state == :not_started
297
+ return @running_state == :running
298
+ end
299
+ end
300
+
301
+ # handle registration of classes
302
+ #
303
+ # service is either a class that includes GRPC::GenericService and whose
304
+ # #new function can be called without argument or any instance of such a
305
+ # class.
306
+ #
307
+ # E.g, after
308
+ #
309
+ # class Divider
310
+ # include GRPC::GenericService
311
+ # rpc :div DivArgs, DivReply # single request, single response
312
+ # def initialize(optional_arg='default option') # no args
313
+ # ...
314
+ # end
315
+ #
316
+ # srv = GRPC::RpcServer.new(...)
317
+ #
318
+ # # Either of these works
319
+ #
320
+ # srv.handle(Divider)
321
+ #
322
+ # # or
323
+ #
324
+ # srv.handle(Divider.new('replace optional arg'))
325
+ #
326
+ # It raises RuntimeError:
327
+ # - if service is not valid service class or object
328
+ # - its handler methods are already registered
329
+ # - if the server is already running
330
+ #
331
+ # @param service [Object|Class] a service class or object as described
332
+ # above
333
+ def handle(service)
334
+ @run_mutex.synchronize do
335
+ unless @running_state == :not_started
336
+ fail 'cannot add services if the server has been started'
337
+ end
338
+ cls = service.is_a?(Class) ? service : service.class
339
+ assert_valid_service_class(cls)
340
+ add_rpc_descs_for(service)
341
+ end
342
+ end
343
+
344
+ # runs the server
345
+ #
346
+ # - if no rpc_descs are registered, this exits immediately, otherwise it
347
+ # continues running permanently and does not return until program exit.
348
+ #
349
+ # - #running? returns true after this is called, until #stop cause the
350
+ # the server to stop.
351
+ def run
352
+ @run_mutex.synchronize do
353
+ fail 'cannot run without registering services' if rpc_descs.size.zero?
354
+ @pool.start
355
+ @server.start
356
+ transition_running_state(:running)
357
+ @run_cond.broadcast
358
+ end
359
+ loop_handle_server_calls
360
+ end
361
+
362
+ alias_method :run_till_terminated, :run
363
+
364
+ # runs the server with signal handlers
365
+ # @param signals
366
+ # List of String, Integer or both representing signals that the user
367
+ # would like to send to the server for graceful shutdown
368
+ # @param wait_interval (optional)
369
+ # Integer seconds that user would like stop_server_thread to poll
370
+ # stop_server
371
+ def run_till_terminated_or_interrupted(signals, wait_interval = 60)
372
+ @stop_server = false
373
+ @stop_server_mu = Mutex.new
374
+ @stop_server_cv = ConditionVariable.new
375
+
376
+ @stop_server_thread = Thread.new do
377
+ loop do
378
+ break if @stop_server
379
+ @stop_server_mu.synchronize do
380
+ @stop_server_cv.wait(@stop_server_mu, wait_interval)
381
+ end
382
+ end
383
+
384
+ # stop is surrounded by mutex, should handle multiple calls to stop
385
+ # correctly
386
+ stop
387
+ end
388
+
389
+ valid_signals = Signal.list
390
+
391
+ # register signal handlers
392
+ signals.each do |sig|
393
+ # input validation
394
+ target_sig = if sig.class == String
395
+ # cut out the SIG prefix to see if valid signal
396
+ sig.upcase.start_with?('SIG') ? sig.upcase[3..-1] : sig.upcase
397
+ else
398
+ sig
399
+ end
400
+
401
+ # register signal traps for all valid signals
402
+ if valid_signals.value?(target_sig) || valid_signals.key?(target_sig)
403
+ Signal.trap(target_sig) do
404
+ @stop_server = true
405
+ @stop_server_cv.broadcast
406
+ end
407
+ else
408
+ fail "#{target_sig} not a valid signal"
409
+ end
410
+ end
411
+
412
+ run
413
+
414
+ @stop_server_thread.join
415
+ end
416
+
417
+ # Sends RESOURCE_EXHAUSTED if there are too many unprocessed jobs
418
+ def available?(an_rpc)
419
+ return an_rpc if @pool.ready_for_work?
420
+ GRPC.logger.warn('no free worker threads currently')
421
+ noop = proc { |x| x }
422
+
423
+ # Create a new active call that knows that metadata hasn't been
424
+ # sent yet
425
+ c = ActiveCall.new(an_rpc.call, noop, noop, an_rpc.deadline,
426
+ metadata_received: true, started: false)
427
+ c.send_status(GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED,
428
+ 'No free threads in thread pool')
429
+ nil
430
+ end
431
+
432
+ # Sends UNIMPLEMENTED if the method is not implemented by this server
433
+ def implemented?(an_rpc)
434
+ mth = an_rpc.method.to_sym
435
+ return an_rpc if rpc_descs.key?(mth)
436
+ GRPC.logger.warn("UNIMPLEMENTED: #{an_rpc}")
437
+ noop = proc { |x| x }
438
+
439
+ # Create a new active call that knows that
440
+ # metadata hasn't been sent yet
441
+ c = ActiveCall.new(an_rpc.call, noop, noop, an_rpc.deadline,
442
+ metadata_received: true, started: false)
443
+ c.send_status(GRPC::Core::StatusCodes::UNIMPLEMENTED, '')
444
+ nil
445
+ end
446
+
447
+ # handles calls to the server
448
+ def loop_handle_server_calls
449
+ fail 'not started' if running_state == :not_started
450
+ while running_state == :running
451
+ begin
452
+ an_rpc = @server.request_call
453
+ break if (!an_rpc.nil?) && an_rpc.call.nil?
454
+ active_call = new_active_server_call(an_rpc)
455
+ unless active_call.nil?
456
+ @pool.schedule(active_call) do |ac|
457
+ c, mth = ac
458
+ begin
459
+ rpc_descs[mth].run_server_method(
460
+ c,
461
+ rpc_handlers[mth],
462
+ @interceptors.build_context
463
+ )
464
+ rescue StandardError
465
+ c.send_status(GRPC::Core::StatusCodes::INTERNAL,
466
+ 'Server handler failed')
467
+ end
468
+ end
469
+ end
470
+ rescue Core::CallError, RuntimeError => e
471
+ # these might happen for various reasons. The correct behavior of
472
+ # the server is to log them and continue, if it's not shutting down.
473
+ if running_state == :running
474
+ GRPC.logger.warn("server call failed: #{e}")
475
+ end
476
+ next
477
+ end
478
+ end
479
+ # @running_state should be :stopping here
480
+ @run_mutex.synchronize do
481
+ transition_running_state(:stopped)
482
+ GRPC.logger.info("stopped: #{self}")
483
+ @server.close
484
+ end
485
+ end
486
+
487
+ def new_active_server_call(an_rpc)
488
+ return nil if an_rpc.nil? || an_rpc.call.nil?
489
+
490
+ # allow the metadata to be accessed from the call
491
+ an_rpc.call.metadata = an_rpc.metadata # attaches md to call for handlers
492
+ connect_md = nil
493
+ unless @connect_md_proc.nil?
494
+ connect_md = @connect_md_proc.call(an_rpc.method, an_rpc.metadata)
495
+ end
496
+
497
+ return nil unless available?(an_rpc)
498
+ return nil unless implemented?(an_rpc)
499
+
500
+ # Create the ActiveCall. Indicate that metadata hasnt been sent yet.
501
+ GRPC.logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
502
+ rpc_desc = rpc_descs[an_rpc.method.to_sym]
503
+ c = ActiveCall.new(an_rpc.call,
504
+ rpc_desc.marshal_proc,
505
+ rpc_desc.unmarshal_proc(:input),
506
+ an_rpc.deadline,
507
+ metadata_received: true,
508
+ started: false,
509
+ metadata_to_send: connect_md)
510
+ c.attach_peer_cert(an_rpc.call.peer_cert)
511
+ mth = an_rpc.method.to_sym
512
+ [c, mth]
513
+ end
514
+
515
+ protected
516
+
517
+ def rpc_descs
518
+ @rpc_descs ||= {}
519
+ end
520
+
521
+ def rpc_handlers
522
+ @rpc_handlers ||= {}
523
+ end
524
+
525
+ def assert_valid_service_class(cls)
526
+ unless cls.include?(GenericService)
527
+ fail "#{cls} must 'include GenericService'"
528
+ end
529
+ fail "#{cls} should specify some rpc descriptions" if
530
+ cls.rpc_descs.size.zero?
531
+ end
532
+
533
+ # This should be called while holding @run_mutex
534
+ def add_rpc_descs_for(service)
535
+ cls = service.is_a?(Class) ? service : service.class
536
+ specs, handlers = (@rpc_descs ||= {}), (@rpc_handlers ||= {})
537
+ cls.rpc_descs.each_pair do |name, spec|
538
+ route = "/#{cls.service_name}/#{name}".to_sym
539
+ fail "already registered: rpc #{route} from #{spec}" if specs.key? route
540
+ specs[route] = spec
541
+ rpc_name = GenericService.underscore(name.to_s).to_sym
542
+ if service.is_a?(Class)
543
+ handlers[route] = cls.new.method(rpc_name)
544
+ else
545
+ handlers[route] = service.method(rpc_name)
546
+ end
547
+ GRPC.logger.info("handling #{route} with #{handlers[route]}")
548
+ end
549
+ end
550
+ end
551
+ end