Skip to content

skip close_on_exec() - #3713

Open
methane wants to merge 2 commits into
benoitc:masterfrom
methane:skip-close-on-exec
Open

skip close_on_exec()#3713
methane wants to merge 2 commits into
benoitc:masterfrom
methane:skip-close-on-exec

Conversation

@methane

@methane methane commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

It is default since in Python 3.4.

https://peps.python.org/pep-0446/

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 273bcfa2ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread gunicorn/workers/base.py
@@ -106,17 +106,9 @@ def init_process(self):
self.PIPE = os.pipe()
for p in self.PIPE:
util.set_non_blocking(p)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore CLOEXEC on worker listener sockets

When application code forks and execs a child without closing file descriptors (for example, subprocess.Popen(..., close_fds=False)), that child now inherits every Gunicorn listener. BaseSocket.set_options() deliberately marks listeners inheritable for the master's re-exec path, so PEP 446 does not protect them; this worker-side loop was what reversed that setting after the fork. A long-lived child can therefore keep the listening port bound after Gunicorn shuts down and prevent a clean restart, so the listeners still need to be made non-inheritable during worker initialization.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Arbitor of gunicorn uses os.fork() instead of Popen(). When creating self.LISTENERS, it is not set to inheritable, so it remains non-inheritable from the parent process. It is not necessary to set it after forking in the child process.

Comment thread gunicorn/util.py
Comment thread gunicorn/arbiter.py
"""
self.log.close_on_exec()

# initialize all signals

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Continue invoking custom logger CLOEXEC hooks

When --logger-class supplies a custom logger whose close_on_exec() handles inherited or explicitly inheritable logging descriptors, this removal silently stops invoking that hook in both the master and workers. PEP 446 only changes defaults for descriptors created by Python and cannot replace custom cleanup logic, so those descriptors can leak through a master re-exec or an exec launched by application code; retain the lifecycle call even if the built-in logger implementation no longer needs to do work.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant