From 906aa4ed9374c0c3d25888e01e62c532bf9a6514 Mon Sep 17 00:00:00 2001 From: gitadmin Date: Sat, 10 Jan 2026 18:35:10 +0300 Subject: [PATCH] =?UTF-8?q?[=D0=92=D0=9E=D0=9B=D0=9A]=20Socker=20timeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tg_publish.py | 197 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 180 insertions(+), 17 deletions(-) diff --git a/tg_publish.py b/tg_publish.py index 52fd2e4..4408bd6 100644 --- a/tg_publish.py +++ b/tg_publish.py @@ -211,7 +211,48 @@ def _send_photo_sync(send_photo_url, image_data, caption, chat_id, disable_notif read=max_timeout ) - return super().init_poolmanager(*args, **kwargs) + pool = super().init_poolmanager(*args, **kwargs) + + # Устанавливаем socket timeout для всех соединений в пуле + # Это критично для операций записи в сокет + # Используем несколько подходов для надежности + try: + if hasattr(pool, 'ConnectionCls') and pool.ConnectionCls: + original_connect = pool.ConnectionCls.connect + def connect_with_socket_timeout(self): + result = original_connect(self) + # Устанавливаем socket timeout после подключения + # Это применяется ко всем операциям с сокетом (read и write) + if hasattr(self, 'sock') and self.sock: + self.sock.settimeout(write_timeout) + return result + pool.ConnectionCls.connect = connect_with_socket_timeout + except Exception: + # Если не удалось установить через ConnectionCls, используем другой подход + pass + + return pool + + def _new_conn(self): + """Создаем новое соединение с установкой socket timeout""" + conn = super()._new_conn() + # Устанавливаем socket timeout для операций записи + try: + if hasattr(conn, 'sock') and conn.sock: + conn.sock.settimeout(write_timeout) + elif hasattr(conn, 'connect'): + # Если соединение еще не создано, перехватываем метод connect + original_connect = conn.connect + def connect_with_timeout(): + result = original_connect() + if hasattr(conn, 'sock') and conn.sock: + conn.sock.settimeout(write_timeout) + return result + conn.connect = connect_with_timeout + except Exception: + # Игнорируем ошибки при установке timeout + pass + return conn # Монтируем кастомный адаптер adapter = CustomHTTPAdapter(max_retries=Retry(total=0)) @@ -260,6 +301,8 @@ def _edit_caption_sync(edit_caption_url, chat_id, message_id, caption, timeout): Returns: requests.Response объект """ + import socket + try: data = { 'chat_id': chat_id, @@ -268,21 +311,77 @@ def _edit_caption_sync(edit_caption_url, chat_id, message_id, caption, timeout): 'parse_mode': 'HTML' } - # Преобразуем timeout в формат, который принимает requests - # requests принимает либо число, либо кортеж (connect, read) + # Извлекаем таймауты if isinstance(timeout, tuple): if len(timeout) >= 3: - # Используем максимальный из read и write timeout connect_timeout, read_timeout, write_timeout = timeout[0], timeout[1], timeout[2] - requests_timeout = (connect_timeout, max(read_timeout, write_timeout)) elif len(timeout) == 2: - requests_timeout = timeout + connect_timeout, read_timeout = timeout[0], timeout[1] + write_timeout = read_timeout else: - requests_timeout = timeout[0] + connect_timeout = read_timeout = write_timeout = timeout[0] else: - requests_timeout = timeout + connect_timeout = read_timeout = write_timeout = timeout - response = requests.post( + # Преобразуем timeout в формат, который принимает requests + requests_timeout = (connect_timeout, max(read_timeout, write_timeout)) + + # Создаем сессию с кастомным адаптером для установки socket timeout + session = requests.Session() + + class CustomHTTPAdapter(HTTPAdapter): + def init_poolmanager(self, *args, **kwargs): + socket_options = kwargs.get('socket_options', []) + socket_options.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) + kwargs['socket_options'] = socket_options + + max_timeout = max(connect_timeout, read_timeout, write_timeout) + if 'timeout' not in kwargs: + kwargs['timeout'] = Urllib3Timeout( + connect=connect_timeout, + read=max_timeout + ) + + pool = super().init_poolmanager(*args, **kwargs) + + # Устанавливаем socket timeout для всех соединений в пуле + try: + if hasattr(pool, 'ConnectionCls') and pool.ConnectionCls: + original_connect = pool.ConnectionCls.connect + def connect_with_socket_timeout(self): + result = original_connect(self) + if hasattr(self, 'sock') and self.sock: + self.sock.settimeout(write_timeout) + return result + pool.ConnectionCls.connect = connect_with_socket_timeout + except Exception: + pass + + return pool + + def _new_conn(self): + """Создаем новое соединение с установкой socket timeout""" + conn = super()._new_conn() + try: + if hasattr(conn, 'sock') and conn.sock: + conn.sock.settimeout(write_timeout) + elif hasattr(conn, 'connect'): + original_connect = conn.connect + def connect_with_timeout(): + result = original_connect() + if hasattr(conn, 'sock') and conn.sock: + conn.sock.settimeout(write_timeout) + return result + conn.connect = connect_with_timeout + except Exception: + pass + return conn + + adapter = CustomHTTPAdapter(max_retries=Retry(total=0)) + session.mount('http://', adapter) + session.mount('https://', adapter) + + response = session.post( edit_caption_url, json=data, timeout=requests_timeout @@ -295,6 +394,9 @@ def _edit_caption_sync(edit_caption_url, chat_id, message_id, caption, timeout): raise except Exception as e: raise + finally: + if 'session' in locals(): + session.close() def _edit_text_sync(edit_text_url, chat_id, message_id, text, timeout): """ @@ -311,6 +413,8 @@ def _edit_text_sync(edit_text_url, chat_id, message_id, text, timeout): Returns: requests.Response объект """ + import socket + try: data = { 'chat_id': chat_id, @@ -320,21 +424,77 @@ def _edit_text_sync(edit_text_url, chat_id, message_id, text, timeout): 'disable_web_page_preview': True } - # Преобразуем timeout в формат, который принимает requests - # requests принимает либо число, либо кортеж (connect, read) + # Извлекаем таймауты if isinstance(timeout, tuple): if len(timeout) >= 3: - # Используем максимальный из read и write timeout connect_timeout, read_timeout, write_timeout = timeout[0], timeout[1], timeout[2] - requests_timeout = (connect_timeout, max(read_timeout, write_timeout)) elif len(timeout) == 2: - requests_timeout = timeout + connect_timeout, read_timeout = timeout[0], timeout[1] + write_timeout = read_timeout else: - requests_timeout = timeout[0] + connect_timeout = read_timeout = write_timeout = timeout[0] else: - requests_timeout = timeout + connect_timeout = read_timeout = write_timeout = timeout - response = requests.post( + # Преобразуем timeout в формат, который принимает requests + requests_timeout = (connect_timeout, max(read_timeout, write_timeout)) + + # Создаем сессию с кастомным адаптером для установки socket timeout + session = requests.Session() + + class CustomHTTPAdapter(HTTPAdapter): + def init_poolmanager(self, *args, **kwargs): + socket_options = kwargs.get('socket_options', []) + socket_options.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)) + kwargs['socket_options'] = socket_options + + max_timeout = max(connect_timeout, read_timeout, write_timeout) + if 'timeout' not in kwargs: + kwargs['timeout'] = Urllib3Timeout( + connect=connect_timeout, + read=max_timeout + ) + + pool = super().init_poolmanager(*args, **kwargs) + + # Устанавливаем socket timeout для всех соединений в пуле + try: + if hasattr(pool, 'ConnectionCls') and pool.ConnectionCls: + original_connect = pool.ConnectionCls.connect + def connect_with_socket_timeout(self): + result = original_connect(self) + if hasattr(self, 'sock') and self.sock: + self.sock.settimeout(write_timeout) + return result + pool.ConnectionCls.connect = connect_with_socket_timeout + except Exception: + pass + + return pool + + def _new_conn(self): + """Создаем новое соединение с установкой socket timeout""" + conn = super()._new_conn() + try: + if hasattr(conn, 'sock') and conn.sock: + conn.sock.settimeout(write_timeout) + elif hasattr(conn, 'connect'): + original_connect = conn.connect + def connect_with_timeout(): + result = original_connect() + if hasattr(conn, 'sock') and conn.sock: + conn.sock.settimeout(write_timeout) + return result + conn.connect = connect_with_timeout + except Exception: + pass + return conn + + adapter = CustomHTTPAdapter(max_retries=Retry(total=0)) + session.mount('http://', adapter) + session.mount('https://', adapter) + + response = session.post( edit_text_url, json=data, timeout=requests_timeout @@ -347,6 +507,9 @@ def _edit_text_sync(edit_text_url, chat_id, message_id, text, timeout): raise except Exception as e: raise + finally: + if 'session' in locals(): + session.close() async def publish_to_tg(vk_post_id): """Публикация одной записи по VK post ID"""