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

fix: unix socket support multi workers #433

Closed

Conversation

Hanaasagi
Copy link
Contributor

@Hanaasagi Hanaasagi commented Sep 22, 2019

@Hanaasagi Hanaasagi force-pushed the fix-unix-socket-in-multi-workers branch 2 times, most recently from 55958e7 to d80dc4a Compare September 25, 2019 14:47
@Hanaasagi Hanaasagi force-pushed the fix-unix-socket-in-multi-workers branch from d80dc4a to 221c76a Compare September 25, 2019 14:53
@Hanaasagi Hanaasagi marked this pull request as ready for review September 26, 2019 03:07
sock = config.bind_unix_socket()
supervisor.run(server.run, sockets=[sock])
sock.close()
os.remove(config.uds)
Copy link
Member

Choose a reason for hiding this comment

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

Curious: Why do we remove the UDS socket here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

From man 7 Unix

Binding to a socket with a filename creates a socket in the filesystem that must be deleted by the caller when it is no longer needed (using unlink(2)). The usual UNIX close-behind semantics apply; the socket can be unlinked at any time and will be finally removed from the filesystem when the last reference to it is closed.

I think there is another problem. If our process crashes, os.remove() will not be called and we’ll have a dangling socket. It seems that we need to check the socket file before bind().


Why haven’t encountered this problem when use one worker and unix socket mode?

Because we use the create_unix_server

uvicorn/uvicorn/main.py

Lines 363 to 373 in e0a77de

elif config.uds is not None:
# Create a socket using UNIX domain socket.
uds_perms = 0o666
if os.path.exists(config.uds):
uds_perms = os.stat(config.uds).st_mode
server = await loop.create_unix_server(create_protocol, path=config.uds)
os.chmod(config.uds, uds_perms)
message = "Uvicorn running on unix socket %s (Press CTRL+C to quit)"
self.logger.info(message % config.uds)
self.servers = [server]

create_unix_server will unlink the socket file before it starts.

https://github.com/python/cpython/blob/0d3fe8ae4961bf551e7d5e42559e2ede1a08fd7c/Lib/asyncio/unix_events.py#L283-L293

info = transport.get_extra_info("peername")
if info is not None and isinstance(info, (list, tuple)) and len(info) == 2:
return (str(info[0]), int(info[1]))
return None
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason why we're changing the None case here?

Copy link
Contributor Author

@Hanaasagi Hanaasagi Oct 8, 2019

Choose a reason for hiding this comment

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

None was displayed in access log.

2019-10-08 15:47:52,870 - INFO - None - "GET / HTTP/1.1" 200
2019-10-08 15:48:00,546 - INFO - None - "GET / HTTP/1.1" 200
2019-10-08 15:48:01,285 - INFO - None - "GET / HTTP/1.1" 200

Or we can fix here

diff --git a/uvicorn/protocols/http/httptools_impl.py b/uvicorn/protocols/http/httptools_impl.py
index 2e1dd90..8b414b2 100644
--- a/uvicorn/protocols/http/httptools_impl.py
+++ b/uvicorn/protocols/http/httptools_impl.py
@@ -436,7 +436,7 @@ class RequestResponseCycle:
             if self.access_log:
                 self.logger.info(
                     '%s - "%s %s HTTP/%s" %d',
-                    self.scope["client"],
+                    self.scope["client"] or "-",
                     self.scope["method"],
                     get_path_with_query_string(self.scope),
                     self.scope["http_version"],

Any good idea, thanks?

@jcwilson
Copy link
Contributor

I just bumped into this today, as well. I can use TCP for now, but would love to help out here if I can.

@gisthere
Copy link

really needed

@Hanaasagi
Copy link
Contributor Author

Emm, I will fix the conflicts recently.

@Roang-zero1
Copy link
Contributor

Both the issue I had #586 and the Issue #722 could also be solved by using the fix proposed in this pull request.
By moving the check to config.bind_socket as proposed in #722 any further additions to watcher types would also be agnostic to the type of socket used.
I am willing to work on refactoring as needed.

@Kludex
Copy link
Sponsor Member

Kludex commented May 15, 2022

I'll close this PR, as #1009 addressed the issue that motivated it.

@Kludex Kludex closed this May 15, 2022
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.

UNIX domain socket raises 503 when workers are used
6 participants