-
-
Notifications
You must be signed in to change notification settings - Fork 749
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
add socket-load-balance flag #2472
base: master
Are you sure you want to change the base?
Conversation
uvicorn/_subprocess.py
Outdated
def get(self) -> socket.socket: | ||
return self._sock | ||
|
||
if (sys.platform == "linux" and hasattr(socket, "SO_REUSEPORT")) or hasattr(socket, "SO_REUSEPORT_LB"): |
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.
Needs python/cpython#124761
c873d00
to
3e2854a
Compare
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 do we need to add a new argument i.e. socket-load-balance
? Can't this behavior be the default? I'd assume people already thinks that's the default.
There's a tradeoff where the default unfair load balancing favours lower latency and the SO_REUSEPORT(_LB) approach favours an even load between processes I suspect most people do want the fair load balancing, however I think it should bed in a bit before we suddenly turn it on by default for everyone. |
started = m.Event() | ||
d = m.dict() | ||
app = functools.partial(lb_app, d, started) | ||
config = Config(app=app, workers=2, socket_load_balance=True, port=0, interface="asgi3") |
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.
this needs a test for two independent calls to Multiprocess(...).run() running on the same port:
def test_bind_to_used_port():
port = ephemeral_port_reserve.reserve()
config = Config(app=app, workers=2, socket_load_balance=True, port=port, interface="asgi3")
with multiprocessing.get_context("spawn").Pool(max_workers=1) as pool:
try:
f1 = pool.apply_async(uvicorn.main, ...)
# wait for started
with pytest.raises(OSError, match="already bound"):
uvicorn.main(...)
finally: pool.terminate()
|
||
class SocketShareRebind: | ||
def __init__(self, sock: socket.socket): | ||
if not (sys.platform == "linux" and hasattr(socket, "SO_REUSEPORT")) or hasattr(socket, "SO_REUSEPORT_LB"): |
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.
Wouldn't it be better to put the logic here in config.bind_socket
?
Just add it to the else, uds and fd don't seem to support SO_REUSEPORT.
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.
hmm I'm not sure about this, I want to make sure the SO_REUSEPORT flag isn't set before the socket is bound so we still fail if another uvicorn is using this port
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.
How about this?
vvanglro@f2b1037
Summary
Fixes #2467
Checklist