Actions
Bug #18940
closed 
  Ruby Ractor fails with IOError when handling higher concurrency
    Bug #18940:
    Ruby Ractor fails with IOError when handling higher concurrency
  
Description
Reproduction server:
require 'socket'
# Set based on CPU count
CONCURRENCY = 8
server = TCPServer.new(8080)
workers = CONCURRENCY.times.map do
  Ractor.new do
    loop do
      # receive TCPSocket
      session = Ractor.recv
      request = session.gets
      puts request
      session.print "HTTP/1.1 200\r\n"
      session.print "Content-Type: text/html\r\n"
      session.print "\r\n"
      session.print "Hello world! Current time is #{Time.now}"
      session.close
    end
  end
end
loop do
  conn, _ = server.accept
  # pass TCPSocket to one of the workers
  workers.sample.send(conn, move: true)
end
run apache benchmark against code above:
ab -n 20000 -c 20 http://localhost:8080/
or run using hey (https://github.com/rakyll/hey):
hey -n 20000 -c 20 http://localhost:8080/
you should see something like this on the benchmark tool side:
Summary:
  Total:	32.9538 secs
  Slowest:	2.6317 secs
  Fastest:	0.0002 secs
  Average:	0.0331 secs
  Requests/sec:	606.9098
Response time histogram:
  0.000 [1]	|
  0.263 [16968]	|■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.527 [1740]	|■■■■
  0.790 [0]	|
  1.053 [0]	|
  1.316 [0]	|
  1.579 [0]	|
  1.842 [0]	|
  2.105 [20]	|
  2.369 [0]	|
  2.632 [6]	|
Latency distribution:
  10% in 0.0008 secs
  25% in 0.0010 secs
  50% in 0.0012 secs
  75% in 0.0016 secs
  90% in 0.0075 secs
  95% in 0.3101 secs
  99% in 0.3175 secs
Details (average, fastest, slowest):
  DNS+dialup:	0.0322 secs, 0.0002 secs, 2.6317 secs
  DNS-lookup:	0.0006 secs, 0.0000 secs, 0.0127 secs
  req write:	0.0001 secs, 0.0000 secs, 0.0095 secs
  resp wait:	0.0007 secs, 0.0000 secs, 0.0140 secs
  resp read:	0.0001 secs, 0.0000 secs, 0.0088 secs
Status code distribution:
  [200]	18735 responses
Error distribution:
  [1231]	Get "http://localhost:8080/": dial tcp [::1]:8080: connect: connection refused
  [16]	Get "http://localhost:8080/": dial tcp [::1]:8080: connect: connection reset by peer
  [1]	Get "http://localhost:8080/": net/http: HTTP/1.x transport connection broken: unexpected EOF
  [1]	Get "http://localhost:8080/": read tcp 127.0.0.1:57078->127.0.0.1:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57054->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57058->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57059->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57062->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57067->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57068->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57069->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57070->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57071->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57072->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57075->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57076->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57087->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57088->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57089->[::1]:8080: read: connection reset by peer
  [1]	Get "http://localhost:8080/": read tcp [::1]:57090->[::1]:8080: read: connection reset by peer
and this on the ruby process:
...
GET / HTTP/1.1
GET / HTTP/1.1
#<Thread:0x0000000100fbf6e8 run> terminated with exception (report_on_exception is true):
ractor.rb:21:in `write': GET / HTTP/1.1
uninitialized stream (IOError)
	from ractor.rb:21:in `print'
	from ractor.rb:21:in `block (3 levels) in <main>'
	from ractor.rb:11:in `loop'
	from ractor.rb:11:in `block (2 levels) in <main>'
GET / HTTP/1.1
GET / HTTP/1.1
Actions