Remote debugging of `rake test` raises `Errno::EADDRINUSE`
Your environment
ruby -v: ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-linux]rdbg -v: rdbg 1.3.4
Describe the bug
remote debugging with rake test raises Errno::EADDRINUSE
To Reproduce Rakefile:
require 'rake/testtask'
Rake::TestTask.new(:test) do |t|
t.test_files = ['test_example.rb']
end
test_example.rb:
require 'minitest/autorun'
class TestExample < Minitest::Test
def test_foo
binding.break
assert_equal(true, true)
end
end
And run in console:
$ rdbg -O -p 12345 -c rake test
And connect from another console and type c:
$ rdbg -A 12345
[5, 14] in ~/.asdf/installs/ruby/3.0.2/bin/rake
5| # The application 'rake' is installed as part of a gem, and
6| # this file is here to facilitate running it.
7| #
8|
9|
=> 10| version = ">= 0.a"
11|
12| str = ARGV.first
13| if str
14| str = str.b[/\A_(.*)_\z/, 1]
=>#0 <main> at ~/.asdf/installs/ruby/3.0.2/bin/rake:10
(rdbg:remote) c # continue command
Then Errno::EADDRINUSE was raised in server console.
$ rdbg -O -p 12345 -c rake test
DEBUGGER: Debugger can attach via TCP/IP (127.0.0.1:12345)
DEBUGGER: wait for debugger connection...
DEBUGGER: Connected.
/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:131: warning: assigned but unused variable - r
DEBUGGER: wait for debugger connection...
#<Thread:0x0000562eb6c48160@DEBUGGER__::Server::reader /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:43 run> terminated with exception (report_on_exception is true):
/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `bind': Address already in use - bind(2) for 127.0.0.1:12345 (Errno::EADDRINUSE)
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `listen'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:765:in `block in tcp_server_sockets'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `each'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `foreach'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:763:in `tcp_server_sockets'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:338:in `accept'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:48:in `block in activate'
["DEBUGGER Exception: /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/thread_client.rb:967",
#<Errno::EADDRINUSE: Address already in use - bind(2) for 127.0.0.1:12345>,
["/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `bind'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `listen'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:765:in `block in tcp_server_sockets'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `each'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `foreach'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:763:in `tcp_server_sockets'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:338:in `accept'",
"/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:48:in `block in activate'"]]
#<Thread:0x0000562eb6c3ff60@DEBUGGER__::SESSION@server /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/session.rb:144 aborting> terminated with exception (report_on_exception is true):
/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `bind': Address already in use - bind(2) for 127.0.0.1:12345 (Errno::EADDRINUSE)
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `listen'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:765:in `block in tcp_server_sockets'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `each'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `foreach'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:763:in `tcp_server_sockets'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:338:in `accept'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:48:in `block in activate'
/home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `bind': Address already in use - bind(2) for 127.0.0.1:12345 (Errno::EADDRINUSE)
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:201:in `listen'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:765:in `block in tcp_server_sockets'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `each'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:227:in `foreach'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/3.0.0/socket.rb:763:in `tcp_server_sockets'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:338:in `accept'
from /home/suke/.asdf/installs/ruby/3.0.2/lib/ruby/gems/3.0.0/gems/debug-1.3.4/lib/debug/server.rb:48:in `block in activate'
rake aborted!
Command failed with status (1)
Tasks: TOP => test
(See full trace by running task with --trace)
DEBUGGER: Disconnected.
Expected behavior
Not raise Errno::EADDRINUSE and debugger stops at binding.break line in test_example.rb.
I'm not sure how the rake test invokes the test process, but I think the following scenario.
(1) Running rake with debugg port == 12345
(2) Create another process for the test (test worker) and tries to open the debug port 12345, but it's already opened at (1).
6966 pts/0 S+ 0:00 ruby /home/ko1/.rbenv/versions/2.7.3/bin/rake test
6994 pts/0 S+ 0:00 sh -c /home/ko1/.rbenv/versions/2.7.3/bin/ruby -w -I"lib" /home/ko1/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/rake-13.0.6/lib/rake/rake_test_loader.rb "test_example.rb"
6995 pts/0 Sl+ 0:00 /home/ko1/.rbenv/versions/2.7.3/bin/ruby -w -Ilib /home/ko1/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/rake-13.0.6/lib/rake/rake_test_loader.rb test_example.rb
On my environment the ps log shows 2 ruby processes are created and confirms (2).
Now I have no idea how to solve it... Hmm.
Two possible solutions:
(1) use port 0. It assigns free port randomly. (2) Disable debugger at the beginning of Rakefile (not implemented yet).
It is big change but
(3) introduce remote proxy server for remote debuggees
It seems orthodox method, but it needs a time.
Now I don't have a good solution on it.
Think I found a similar problem. See: https://github.com/connorshea/vscode-ruby-test-adapter/issues/92#issuecomment-1191477785
Wow rdbg is used by another project ;p