Avoid port conflict in TCP/IP mode in processes that fork
Problem
When using rdbg with the --port option, I encounter an issue when the process forks, leading to the error:
Address already in use - bind(2) for IP:PORT (Errno::EADDRINUSE)
In my case, I'm using solid_queue, which in its basic configuration starts a Supervisor, Worker, and Dispatcher. This results in multiple processes, and since they all attempt to bind to the same specified port, a conflict occurs.
Feature Request
Change port option in rdbg so it allows specifying a range or list of ports. This would enable the debugger to iterate over the provided range, trying the next available port if one is already in use.
Proposed Solution
Allow rdbg to accept a port range or a list of ports, which it could iterate through to find an open one. For example:
rdbg --port 3003-3005 -n --open -c "./bin/jobs"
In this case, the UI_TcpServer class would attempt to bind to port 3003 first, and if that port is unavailable, it would continue trying 3004, 3005, and so on until it finds an open port.
This would greatly improve the usability of rdbg in environments where multiple processes may be spawned and need to communicate with the debugger.
Additional Context
This issue is particularly relevant in systems with forking processes, such as job queues (e.g., solid_queue), where multiple components (e.g., Supervisor, Worker, Dispatcher) are started. The ability to define a port range would help avoid conflicts and make debugging smoother.
f this enhancement is of interest to the maintainers, I would be happy to contribute by implementing it. Please let me know if this would be a welcome addition.
Thank you for considering this enhancement!
I found that the order in which solid_queue starts its processes is non-deterministic, so relying on a range of ports may not be a reliable solution. I wouldn't be able to predict which port my worker process would be running on.
An alternative approach could be to introduce a REGEX parameter, which would allow the TCP/IP connection to only start when the process information matches the given pattern. This way, the debugger could attach to the correct process based on more specific criteria, potentially avoiding the port conflict issue altogether.
Hopefully this PR would solve that.
@crystianwendel @gerymate were you guys able to make it work with vscode/cursor? I currently have this setup 👇, which solves the issue of the conflicting port address, but in VS Code, when I attach with rdbg, the terminal outputs "DEBUGGER[solid-queue-worker(1.2.1): waiting for jobs in *#35199]: Connected." but doesn't stop at the breakpoints set in vscode, only if I put a debugger in there.
RUBY_DEBUG_OPEN=true RUBY_DEBUG_PORT_RANGE=10 RUBY_DEBUG_PORT=3600 bin/jobs
I was only able to make it work with a process regex.
I couldn't make a PR or somethig, but this is how i did it:
https://github.com/ruby/debug/compare/master...crystianwendel:debug:master
And my procfile solidqueue line is:
worker: bundle exec rdbg --port 3003 --proc_regex "\Asolid-queue-worker" -n --open --host 0.0.0.0 -c "./bin/jobs"
@marcelolx
Thanks for sharing @crystianwendel — I was able to make it work with the following setup
Procfile.dev
web: unset PORT && RUBY_DEBUG_OPEN=true RUBY_DEBUG_PORT=3499 bin/rails s
jobs: RUBY_DEBUG_OPEN=true RUBY_DEBUG_PORT=3500 RUBY_DEBUG_PORT_RANGE=2 bin/jobs
.vscode/launch.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "rdbg",
"name": "rails server",
"request": "attach",
"localfs": true,
"debugPort": "3499"
},
{
"type": "rdbg",
"name": "background jobs",
"request": "attach",
"localfs": true,
"debugPort": "3502"
},
]
}
Obviously, I still run the risk of what you mentioned I found that the order in which solid_queue starts its processes is non-deterministic, but so far, most of the time, the worker picked up the last port 3502, so it has been ok for me.
The issue preventing me from debugging in VS Code was that I was missing the localfs: true setting in the launch.json, which meant the debugger couldn't find the file I was adding a breakpoint to.