Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ResourceWarning: unclosed socket #1812

Open
YoniChechik opened this issue Jan 15, 2025 · 5 comments · Fixed by #1826
Open

ResourceWarning: unclosed socket #1812

YoniChechik opened this issue Jan 15, 2025 · 5 comments · Fixed by #1826
Assignees
Labels
Fixed in next release This issue has been fixed, but won't be available to customers until the next release. needs repro Issue has not been reproduced yet

Comments

@YoniChechik
Copy link

Environment data

  • debugpy version: 1.8.9
  • OS and version: linux ubuntu 22.04 host via ssh via docker devcontainer (nvidia/cuda:12.1.1-runtime-ubuntu22.04)
  • Python version: uv, python 3.12.8
  • Using VS Code or Visual Studio: vscode 1.96.3

Actual behavior

getting unclosed socket warning only when running via debbuger (only extension installed is python + pylance + debugpy):

Exception ignored in: <socket.socket fd=5, family=2, type=1, proto=0, laddr=('127.0.0.1', 57946), raddr=('127.0.0.1', 33845)>
ResourceWarning: unclosed <socket.socket fd=5, family=2, type=1, proto=0, laddr=('127.0.0.1', 57946), raddr=('127.0.0.1', 33845)>

Expected behavior

should not pop

Steps to reproduce:

here is a full code repro:

import time
import warnings
from multiprocessing import Process, set_start_method

warnings.filterwarnings("error")


def script_runner():
    def decorate(func):
        def wrapper(*args, **kwargs):
            set_start_method("spawn")
            func(*args, **kwargs)

        return wrapper

    return decorate


@script_runner()
def main():
    processes = [Process(target=worker_function, args=(f"Worker-{i}",)) for i in range(5)]

    # Start all processes
    for process in processes:
        process.start()

    # Wait for all processes to complete
    for process in processes:
        process.join()

    print("All processes have completed.")


def worker_function(name: str) -> None:
    print(f"Process {name} is starting")
    time.sleep(2)  # Simulate work
    print(f"Process {name} has finished")


if __name__ == "__main__":
    # Create multiple processes
    main()

output:

Process Worker-2 is starting
Process Worker-0 is starting
Process Worker-3 is starting
Process Worker-1 is starting
Process Worker-2 has finished
Process Worker-4 is starting
Process Worker-0 has finished
Exception ignored in: <socket.socket fd=5, family=2, type=1, proto=0, laddr=('127.0.0.1', 57916), raddr=('127.0.0.1', 33845)>
ResourceWarning: unclosed <socket.socket fd=5, family=2, type=1, proto=0, laddr=('127.0.0.1', 57916), raddr=('127.0.0.1', 33845)>
Process Worker-3 has finished
Exception ignored in: <socket.socket fd=5, family=2, type=1, proto=0, laddr=('127.0.0.1', 57946), raddr=('127.0.0.1', 33845)>
ResourceWarning: unclosed <socket.socket fd=5, family=2, type=1, proto=0, laddr=('127.0.0.1', 57946), raddr=('127.0.0.1', 33845)>
Process Worker-1 has finished
Process Worker-4 has finished
All processes have completed.
@github-actions github-actions bot added the needs repro Issue has not been reproduced yet label Jan 15, 2025
@rchiodo
Copy link
Contributor

rchiodo commented Jan 15, 2025

Thanks for the issue, but I don't think this is something we'd bother fixing.

@rchiodo rchiodo closed this as completed Jan 15, 2025
@bersbersbers
Copy link
Contributor

I have come across essentially the same issue. In my eyes, despite the length of the example code above, the problem lies more or less in warnings.filterwarnings("error") - this code already reproduces the issue:

echo import warnings; warnings.filterwarnings("error") > bug.py  
debugpy --listen 5000 bug.py

That it's a very old issue rooted deep in the Python code. However, if the very useful discussion in https://emptysqua.re/blog/against-resourcewarnings-in-python-3/#comment-514722438 is still current, that warning is off by default, and

If you don't override the warnings filters (or use a library or test framework that does so on your behalf), then you won't see it.

So modifying that warnings filter more carefully might fix the warnings output.

Still, since this warning

  • is seen time and time again over the Python history,
  • is unlikely to be fixed any time soon,
  • does not give any indication where it is actually emitted, and thus
  • carries a lot of potential for confusion (I just spent an hour convincing myself that my large Python code base does not have a backdoor that opens a socket behind my back),

... I wonder if debugpy could go ahead and just explicitly close their socket(s) instead of relying on the Python garbage collector to do so. Happy to help with a PR if someone can point me into the right direction (any maybe hint at why this is not an obvious one-liner, if it isn't).

@rchiodo
Copy link
Contributor

rchiodo commented Feb 3, 2025

This might be where you'd start. It's the handling of shutting down when the debugger is exiting:

https://vscode.dev/github/microsoft/debugpy/blob/main/src/debugpy/adapter/sessions.py#L135

@bersbersbers
Copy link
Contributor

Thanks, I think I got somewhere!

Instructions:

rem Install https://marketplace.visualstudio.com/items?itemName=ms-python.debugpy, v2024.14.0
cd %USERPROFILE%\.vscode\extensions\ms-python.debugpy-2024.14.0-win32-x64\bundled\libs
echo import warnings; warnings.filterwarnings("error") > bug.py  
set PYDEVD_DISABLE_FILE_VALIDATION=1

python -m debugpy --listen 5000 bug.py

See

Exception ignored in: <socket.socket fd=740, family=2, type=1, proto=0, laddr=('127.0.0.1', 54606), raddr=('127.0.0.1', 54604)>
ResourceWarning: unclosed <socket.socket fd=740, family=2, type=1, proto=0, laddr=('127.0.0.1', 54606), raddr=('127.0.0.1', 54604)>

Then replace debugpy\_vendored\pydevd\pydevd.py with the version from https://github.com/bersbersbers/debugpy/commit/47f1f4e93d7ac6d4496cc2b736967777e52cb7ea.

Re-run

python -m debugpy --listen 5000 bug.py

See

(nothing)

Voila! I am 99% sure there is better location for the closing of the socket, but I am happy I got this prototype to begin with.

@bersbersbers
Copy link
Contributor

For the record, simpler reproduction checks not requiring VS Code at all: checkout debugpy and run

C:\Git\debugpy\src>python -m debugpy --listen 5000 -c "import warnings; warnings.filterwarnings('error')"

rchiodo pushed a commit that referenced this issue Feb 5, 2025
* Fix #1812, first try

* Prevent tries to close socket multiple times
@rchiodo rchiodo added the Fixed in next release This issue has been fixed, but won't be available to customers until the next release. label Feb 5, 2025
@rchiodo rchiodo reopened this Feb 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Fixed in next release This issue has been fixed, but won't be available to customers until the next release. needs repro Issue has not been reproduced yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants