watchdog as possible fix winerror 64

This commit is contained in:
Flowseal
2026-06-26 16:44:13 +03:00
parent 43bca3a71b
commit eb22fadb7a
+62 -19
View File
@@ -35,6 +35,8 @@ log = logging.getLogger('tg-mtproto-proxy')
DC_FAIL_COOLDOWN = 30.0 DC_FAIL_COOLDOWN = 30.0
WS_FAIL_TIMEOUT = 2.0 WS_FAIL_TIMEOUT = 2.0
LISTENER_CHECK_INTERVAL = 5.0
LISTENER_RESTART_DELAY = 0.5
ws_blacklist: Set[str] = set() ws_blacklist: Set[str] = set()
dc_fail_until: Dict[str, float] = {} dc_fail_until: Dict[str, float] = {}
@@ -511,43 +513,84 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
await ws_pool.warmup() await ws_pool.warmup()
await cf_worker_pool.warmup() await cf_worker_pool.warmup()
async def _quiet_cancel(t):
if not t.done():
t.cancel()
try: try:
async with server: await t
if stop_event: except (asyncio.CancelledError, Exception):
pass
try:
while True:
serve_task = asyncio.create_task(server.serve_forever()) serve_task = asyncio.create_task(server.serve_forever())
stop_task = asyncio.create_task(stop_event.wait()) stop_task = (asyncio.create_task(stop_event.wait())
if stop_event else None)
async def _listener_watchdog():
while True:
await asyncio.sleep(LISTENER_CHECK_INTERVAL)
socks = server.sockets
if not socks or all(s.fileno() < 0 for s in socks):
return
watchdog_task = asyncio.create_task(_listener_watchdog())
waiters = [serve_task, watchdog_task]
if stop_task is not None:
waiters.append(stop_task)
done, _ = await asyncio.wait( done, _ = await asyncio.wait(
(serve_task, stop_task), waiters, return_when=asyncio.FIRST_COMPLETED)
return_when=asyncio.FIRST_COMPLETED,
) if stop_task is not None and stop_task in done:
if stop_task in done:
for task in list(_client_tasks): for task in list(_client_tasks):
task.cancel() task.cancel()
if _client_tasks: if _client_tasks:
await asyncio.gather( await asyncio.gather(
*_client_tasks, return_exceptions=True) *_client_tasks, return_exceptions=True)
if not serve_task.done(): await _quiet_cancel(watchdog_task)
serve_task.cancel() await _quiet_cancel(serve_task)
try:
await serve_task
except asyncio.CancelledError:
pass
server.close() server.close()
await server.wait_closed() await server.wait_closed()
else: break
stop_task.cancel()
await _quiet_cancel(watchdog_task)
await _quiet_cancel(serve_task)
log.warning(
"Listening socket died (OS accept error, e.g. WinError 64); "
"restarting server")
server.close()
try: try:
await stop_task await server.wait_closed()
except asyncio.CancelledError: except Exception:
pass pass
else: await asyncio.sleep(LISTENER_RESTART_DELAY)
await server.serve_forever() try:
server = await asyncio.start_server(
client_cb, proxy_config.host, proxy_config.port)
except OSError as exc:
log.error("Failed to restart server: %s", repr(exc))
break
_server_instance = server
for sock in server.sockets:
try:
sock.setsockopt(
_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1)
except (OSError, AttributeError):
pass
log.warning("Server restored, listening on %s:%d",
proxy_config.host, proxy_config.port)
finally: finally:
log_stats_task.cancel() log_stats_task.cancel()
try: try:
await log_stats_task await log_stats_task
except asyncio.CancelledError: except asyncio.CancelledError:
pass pass
try:
server.close()
await server.wait_closed()
except Exception:
pass
_server_instance = None _server_instance = None