Keep the same port across app restarts
The port probe did a plain bind() without SO_REUSEADDR, so TIME_WAIT connections left by the previous instance (e.g. the in-app update restart) made the port look occupied and the app hopped to the next one. Probe with SO_REUSEADDR like Werkzeug binds, and give the requested port a 10-second grace period before auto-incrementing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
679f91da2c
commit
d6bf80a68a
2 files changed
+28
-7
No files matched your search
+26
-7
@@ -2261,14 +2261,33 @@ Example --settings file with SMTP:
|
||||
|
||||
# Find a free port — auto-increment from the requested port if in use.
|
||||
import socket as _socket
|
||||
|
||||
def _can_bind(p: int, host: str) -> bool:
|
||||
with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as s:
|
||||
# Probe with SO_REUSEADDR, matching how Werkzeug binds.
|
||||
# Without it, connections left in TIME_WAIT by a previous
|
||||
# instance (e.g. the in-app update restart) make the port
|
||||
# look occupied and the app silently moves to the next one.
|
||||
s.setsockopt(_socket.SOL_SOCKET, _socket.SO_REUSEADDR, 1)
|
||||
try:
|
||||
s.bind((host, p))
|
||||
return True
|
||||
except OSError:
|
||||
return False
|
||||
|
||||
def _find_free_port(start: int, host: str) -> int:
|
||||
for p in range(start, start + 100):
|
||||
with _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) as s:
|
||||
try:
|
||||
s.bind((host, p))
|
||||
return p
|
||||
except OSError:
|
||||
continue
|
||||
# Give the requested port a grace period — after a self-restart
|
||||
# the previous process may not have released it yet.
|
||||
deadline = time.time() + 10
|
||||
while True:
|
||||
if _can_bind(start, host):
|
||||
return start
|
||||
if time.time() >= deadline:
|
||||
break
|
||||
time.sleep(0.5)
|
||||
for p in range(start + 1, start + 100):
|
||||
if _can_bind(p, host):
|
||||
return p
|
||||
raise RuntimeError(f"No free port found in range {start}–{start + 99}")
|
||||
|
||||
actual_port = _find_free_port(args.port, args.host)
|
||||
|
||||
Reference in new issue
Block a user