killed_client_thread_driver.rb 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #!/usr/bin/env ruby
  2. # Copyright 2016 gRPC authors.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. require_relative './end2end_common'
  16. # Service that sleeps for a long time upon receiving an 'echo request'
  17. # Also, this notifies @call_started_cv once it has received a request.
  18. class SleepingEchoServerImpl < Echo::EchoServer::Service
  19. def initialize(call_started, call_started_mu, call_started_cv)
  20. @call_started = call_started
  21. @call_started_mu = call_started_mu
  22. @call_started_cv = call_started_cv
  23. end
  24. def echo(echo_req, _)
  25. @call_started_mu.synchronize do
  26. @call_started.set_true
  27. @call_started_cv.signal
  28. end
  29. sleep 1000
  30. Echo::EchoReply.new(response: echo_req.request)
  31. end
  32. end
  33. # Mutable boolean
  34. class BoolHolder
  35. attr_reader :val
  36. def init
  37. @val = false
  38. end
  39. def set_true
  40. @val = true
  41. end
  42. end
  43. def main
  44. STDERR.puts 'start server'
  45. call_started = BoolHolder.new
  46. call_started_mu = Mutex.new
  47. call_started_cv = ConditionVariable.new
  48. service_impl = SleepingEchoServerImpl.new(call_started,
  49. call_started_mu,
  50. call_started_cv)
  51. server_runner = ServerRunner.new(service_impl)
  52. server_port = server_runner.run
  53. STDERR.puts 'start client'
  54. _, client_pid = start_client('killed_client_thread_client.rb',
  55. server_port)
  56. call_started_mu.synchronize do
  57. call_started_cv.wait(call_started_mu) until call_started.val
  58. end
  59. # SIGINT the child process now that it's
  60. # in the middle of an RPC (happening on a non-main thread)
  61. Process.kill('SIGINT', client_pid)
  62. STDERR.puts 'sent shutdown'
  63. begin
  64. Timeout.timeout(10) do
  65. Process.wait(client_pid)
  66. end
  67. rescue Timeout::Error
  68. STDERR.puts "timeout wait for client pid #{client_pid}"
  69. Process.kill('SIGKILL', client_pid)
  70. Process.wait(client_pid)
  71. STDERR.puts 'killed client child'
  72. raise 'Timed out waiting for client process. ' \
  73. 'It likely hangs when killed while in the middle of an rpc'
  74. end
  75. client_exit_code = $CHILD_STATUS
  76. if client_exit_code.termsig != 2 # SIGINT
  77. fail 'expected client exit from SIGINT ' \
  78. "but got child status: #{client_exit_code}"
  79. end
  80. server_runner.stop
  81. end
  82. main