[ВОЛК] очередная отладка таймаутов
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-01-10 18:13:25 +03:00
parent 8087908c27
commit 538213eae9
2 changed files with 65 additions and 11 deletions
+2 -2
View File
@@ -61,11 +61,11 @@ MDB_PW = 'T38tU83r69'
# Debug bot @posto_1638_bot # Debug bot @posto_1638_bot
# BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U" # BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U"
# @info_1638_bot # @info_1638_bot
# POSTER_BOT_TOKEN = "8215624618:AAF6VtqRtFr4twFRTiTjedSDE6txkbIy6rc" POSTER_BOT_TOKEN = "8215624618:AAF6VtqRtFr4twFRTiTjedSDE6txkbIy6rc"
# VOLK production bot @VOLK_informer_bot # VOLK production bot @VOLK_informer_bot
# POSTER_BOT_TOKEN = "8279661544:AAEsJee6icCUn_AbWxhDpk2CLxQhzaartuI" # POSTER_BOT_TOKEN = "8279661544:AAEsJee6icCUn_AbWxhDpk2CLxQhzaartuI"
# VOLK backup production bot @VOLK_informer2_bot # VOLK backup production bot @VOLK_informer2_bot
POSTER_BOT_TOKEN = "8001674071:AAFyGW4xibAFnuApEaSJvshqEyYHmD7RRts" # POSTER_BOT_TOKEN = "8001674071:AAFyGW4xibAFnuApEaSJvshqEyYHmD7RRts"
# VOLK responder bot # VOLK responder bot
# RESPONDER_BOT_TOKEN = "8072579275:AAFiyKN1EPPnP5ZVZNTDGEriYJf1xADbfsY" # RESPONDER_BOT_TOKEN = "8072579275:AAFiyKN1EPPnP5ZVZNTDGEriYJf1xADbfsY"
# RESPONDER_BOT_NAME = "VOLK_responder_bot" # RESPONDER_BOT_NAME = "VOLK_responder_bot"
+63 -9
View File
@@ -8,6 +8,9 @@ import json
import re import re
import httpx import httpx
import requests import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
from urllib3 import Timeout as Urllib3Timeout
import traceback import traceback
import io import io
import sys import sys
@@ -153,11 +156,14 @@ def _send_photo_sync(send_photo_url, image_data, caption, chat_id, disable_notif
caption: Подпись к фото caption: Подпись к фото
chat_id: ID чата/канала chat_id: ID чата/канала
disable_notification: Отключить уведомления disable_notification: Отключить уведомления
timeout: Кортеж (connect_timeout, read_timeout) или число для общего таймаута timeout: Кортеж (connect_timeout, read_timeout, write_timeout) или число для общего таймаута
Returns: Returns:
requests.Response объект requests.Response объект
""" """
import socket
from urllib3.connection import HTTPSConnection, HTTPConnection
try: try:
# Используем requests для стабильной работы в gunicorn # Используем requests для стабильной работы в gunicorn
# requests более надежен для синхронных операций в контексте WSGI # requests более надежен для синхронных операций в контексте WSGI
@@ -172,17 +178,59 @@ def _send_photo_sync(send_photo_url, image_data, caption, chat_id, disable_notif
'disable_notification': str(disable_notification).lower() 'disable_notification': str(disable_notification).lower()
} }
# Извлекаем таймауты из кортежа
if isinstance(timeout, tuple):
if len(timeout) >= 3:
connect_timeout, read_timeout, write_timeout = timeout[0], timeout[1], timeout[2]
elif len(timeout) == 2:
connect_timeout, read_timeout = timeout[0], timeout[1]
write_timeout = read_timeout # Используем read timeout для write
else:
connect_timeout = read_timeout = write_timeout = timeout[0]
else:
connect_timeout = read_timeout = write_timeout = timeout
# Создаем сессию с кастомным адаптером
session = requests.Session()
# Создаем кастомный HTTPAdapter с установкой socket timeout
class CustomHTTPAdapter(HTTPAdapter):
def init_poolmanager(self, *args, **kwargs):
# Устанавливаем socket timeout через socket_options
# Это применяется ко всем операциям с сокетом (read и write)
socket_options = kwargs.get('socket_options', [])
socket_options.append((socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1))
kwargs['socket_options'] = socket_options
pool = super().init_poolmanager(*args, **kwargs)
# Устанавливаем socket timeout для всех соединений в пуле
# Это применяется ко всем операциям с сокетом (read и write)
original_connect = pool.ConnectionCls.connect
def connect_with_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_timeout
return pool
# Монтируем кастомный адаптер
adapter = CustomHTTPAdapter(max_retries=Retry(total=0))
session.mount('http://', adapter)
session.mount('https://', adapter)
# Отправляем запрос с увеличенным таймаутом # Отправляем запрос с увеличенным таймаутом
# requests.post принимает timeout как кортеж (connect, read) или число # Используем максимальный таймаут для всех операций
response = requests.post( max_timeout = max(connect_timeout, read_timeout, write_timeout)
response = session.post(
send_photo_url, send_photo_url,
files=files, files=files,
data=data, data=data,
timeout=timeout, timeout=(connect_timeout, max_timeout), # (connect, read)
stream=False # Отключаем потоковую передачу для стабильности stream=False # Отключаем потоковую передачу для стабильности
) )
return response return response
except requests.exceptions.Timeout as e: except requests.exceptions.Timeout as e:
# Пробрасываем таймаут как есть, чтобы его можно было обработать выше # Пробрасываем таймаут как есть, чтобы его можно было обработать выше
raise raise
@@ -192,6 +240,10 @@ def _send_photo_sync(send_photo_url, image_data, caption, chat_id, disable_notif
except Exception as e: except Exception as e:
# Пробрасываем остальные исключения как есть # Пробрасываем остальные исключения как есть
raise raise
finally:
# Закрываем сессию
if 'session' in locals():
session.close()
def _edit_caption_sync(edit_caption_url, chat_id, message_id, caption, timeout): def _edit_caption_sync(edit_caption_url, chat_id, message_id, caption, timeout):
""" """
@@ -404,9 +456,9 @@ async def publish_to_tg(vk_post_id):
# Вызываем синхронную функцию через asyncio.to_thread() # Вызываем синхронную функцию через asyncio.to_thread()
# Это позволяет избежать проблем с event loop в gunicorn # Это позволяет избежать проблем с event loop в gunicorn
try: try:
# Используем кортеж для таймаута: (connect, read) # Используем кортеж для таймаута: (connect, read, write)
# requests использует один таймаут для всех операций, поэтому используем максимальный # write_timeout применяется к операциям записи в сокет
timeout_tuple = (10.0, write_timeout) # (connect, read/write) timeout_tuple = (10.0, write_timeout, write_timeout) # (connect, read, write)
photo_response = await asyncio.to_thread( photo_response = await asyncio.to_thread(
_send_photo_sync, _send_photo_sync,
@@ -631,7 +683,8 @@ async def publish_to_tg(vk_post_id):
edit_caption_success = False edit_caption_success = False
try: try:
# Используем requests через asyncio.to_thread() для стабильной работы в gunicorn # Используем requests через asyncio.to_thread() для стабильной работы в gunicorn
edit_timeout = (10.0, 30.0) # (connect, read) # Увеличиваем таймаут для редактирования caption
edit_timeout = (10.0, 60.0, 60.0) # (connect, read, write)
edit_caption_response = await asyncio.to_thread( edit_caption_response = await asyncio.to_thread(
_edit_caption_sync, _edit_caption_sync,
@@ -697,7 +750,8 @@ async def publish_to_tg(vk_post_id):
edit_text_success = False edit_text_success = False
try: try:
# Используем requests через asyncio.to_thread() для стабильной работы в gunicorn # Используем requests через asyncio.to_thread() для стабильной работы в gunicorn
edit_timeout = (10.0, 30.0) # (connect, read) # Увеличиваем таймаут для редактирования текста
edit_timeout = (10.0, 60.0, 60.0) # (connect, read, write)
edit_text_response = await asyncio.to_thread( edit_text_response = await asyncio.to_thread(
_edit_text_sync, _edit_text_sync,