Release v0.51.280 — Release IV (stage-p3i — Windows self-update restart fix #3647) (#3687)
Some checks failed
Release & Docker / release (push) Has been cancelled

* fix(updates): Windows self-update restart via detached Popen + bind-retry (os.execv doesn't replace proc on Windows) (#3647)

Co-authored-by: jja881 <jja881@users.noreply.github.com>

* docs(changelog): v0.51.280 — Release IV (stage-p3i)

---------

Co-authored-by: nesquena-hermes <[email protected]>
Co-authored-by: jja881 <jja881@users.noreply.github.com>
This commit is contained in:
nesquena-hermes
2026-06-05 14:54:59 -07:00
committed by GitHub
parent b5caf83ff9
commit ffc1ab6fd6
3 changed files with 53 additions and 4 deletions

View File

@@ -210,7 +210,24 @@ class QuietHTTPServer(ThreadingHTTPServer):
self.allow_reuse_address = False
SO_EXCLUSIVEADDRUSE = getattr(socket, 'SO_EXCLUSIVEADDRUSE', -5)
self.socket.setsockopt(socket.SOL_SOCKET, SO_EXCLUSIVEADDRUSE, 1)
super().server_bind()
# Retry bind on Windows to handle the case where a previous
# process (e.g. during self-update) is still releasing the port.
# The old process calls os._exit(0) which starts tearing down
# its socket, but with SO_EXCLUSIVEADDRUSE the OS blocks new
# binds until the teardown completes. Retry for up to 10 s.
max_retries = 20
retry_delay = 0.5
for attempt in range(max_retries):
try:
super().server_bind()
return
except OSError as e:
if e.winerror == 10048 and attempt < max_retries - 1: # WSAEADDRINUSE
time.sleep(retry_delay)
else:
raise
else:
super().server_bind()
def _handle_request_noblock(self):
"""Record accept-loop progress before dispatching a request handler.