-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Close open resources #3250
base: master
Are you sure you want to change the base?
Close open resources #3250
Conversation
This resolves a `ResourceWarning` caused by the test suite.
This ensures that unclosed resources will be caught in CI
Huh. Making warnings fatal keeps CI all green despite the garbage collected file handle in Line 246 in 79b9a52
Suggested followup: master...pajod:gunicorn:close-resources-followup No objections, though I suspect also a few DeprecationWarnings currently not in CI will pop up - not necessarily a bad thing. Linking related issues for easier discovery: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please answer to incline comment. Also revert the change corresponding to the socket. This is not needed.
try: | ||
self.sock = socket.socket(address_family, socket.SOCK_DGRAM) | ||
self.sock.connect(cfg.statsd_host) | ||
except Exception: | ||
self.sock = None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't the garbage collector takes care about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ddon't try to close the cocket there. None should be ok.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't the garbage collector takes care about it?
Even GC reliably working in our favor is no excuse. We should never make the WSGI application developer figure out which warning is our fault and harmless, and which one is triggered by their code and should be looked into.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
closing sockets like this is unwanted also. The socket is not supposed to be created at this step. So just making it going to None will be enough.
However this is missing a more elaborated error handler to display what's going wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've answered more fully below; the summary is that relying on the garbage collector without calling .close()
will cause Python to throw a ResourceWarning
. Simply creating the socket instance is sufficient to cause this problem, as demonstrated in the reproducer code I wrote below.
@@ -76,6 +76,9 @@ main = "gunicorn.app.pasterapp:serve" | |||
norecursedirs = ["examples", "lib", "local", "src"] | |||
testpaths = ["tests/"] | |||
addopts = "--assert=plain --cov=gunicorn --cov-report=xml" | |||
filterwarnings = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've answered more fully below; the summary is that this ensures the test suite catches ResourceWarning
s that might be introduced in the future.
Hello Benoit! Thanks for reviewing this PR. I'm responding here to offer a complete understanding of the changes.
It will, but if the socket's
None is insufficient. Here's a reproducer: import socket
import warnings
# Configure Python to stop ignoring `ResourceWarning`s.
warnings.filterwarnings("always")
def rely_on_gc():
# When `s` is reassigned, gc will clean up the socket
# and a ResourceWarning will be thrown.
print("rely_on_gc(): start")
s = socket.socket()
s = None
print("rely_on_gc(): end")
def explicit_close():
print("explicit_close(): start")
s = socket.socket()
s.close()
s = None
print("explicit_close(): end")
rely_on_gc()
print("---")
explicit_close() And here's the output: $ python demo.py
rely_on_gc(): start
/home/kurt/dev/demo.py:13: ResourceWarning: unclosed <socket.socket fd=3, family=2, type=1, proto=0, laddr=('0.0.0.0', 0)>
s = None
ResourceWarning: Enable tracemalloc to get the object allocation traceback
rely_on_gc(): end
---
explicit_close(): start
explicit_close(): end As demonstrated above, setting
This was actually the first step I took to reveal where Adding this configuration to the test suite ensures that future code changes that introduce
That change is the entire point of this PR -- it guarantees that Python does not throw a |
Hello @benoitc! Please let me know if you have additional questions or feedback. Thanks! |
There are several places in the test suite and in the production code where resources are opened but not closed. This results in
ResourceWarning
s while the test suite is running (which Python normally ignores), and is revealed by setting pytest'sfilterwarning=errors
.This PR introduces the following changes:
If this is merged, it will help ensure that gunicorn consistently closes resources (files and sockets).