This commit is contained in:
+56
-60
@@ -260,26 +260,25 @@ async def publish_to_tg(vk_post_id):
|
|||||||
write_timeout = max(120.0, 60.0 + (file_size_mb * 10.0))
|
write_timeout = max(120.0, 60.0 + (file_size_mb * 10.0))
|
||||||
logger.info(f"Размер файла: {file_size_mb:.2f} МБ, таймаут на запись: {write_timeout:.1f} секунд")
|
logger.info(f"Размер файла: {file_size_mb:.2f} МБ, таймаут на запись: {write_timeout:.1f} секунд")
|
||||||
|
|
||||||
# Для больших файлов используем синхронный клиент, чтобы избежать проблем с event loop
|
# Используем синхронный httpx клиент для отправки файлов
|
||||||
# Синхронный клиент более стабилен при работе в отдельном потоке с gunicorn
|
# Это необходимо для стабильной работы с gunicorn, который использует синхронные воркеры
|
||||||
use_sync_client = file_size_mb > 0.5 # Для файлов больше 0.5 МБ используем синхронный клиент
|
# Синхронный клиент не зависит от event loop и работает стабильно в отдельном потоке
|
||||||
|
logger.info(f"Используем синхронный httpx клиент для файла размером {file_size_mb:.2f} МБ")
|
||||||
|
|
||||||
# Логируем время начала запроса
|
# Логируем время начала запроса
|
||||||
request_start_time = time.time()
|
request_start_time = time.time()
|
||||||
logger.info(f"Начало запроса отправки фото в {datetime.now(timezone.utc).isoformat()}")
|
logger.info(f"Начало запроса отправки фото в {datetime.now(timezone.utc).isoformat()}")
|
||||||
|
|
||||||
if use_sync_client:
|
# Используем синхронный httpx клиент
|
||||||
logger.info(f"Используем синхронный httpx клиент для файла размером {file_size_mb:.2f} МБ")
|
import httpx as httpx_sync
|
||||||
|
upload_timeout_config = httpx_sync.Timeout(
|
||||||
# Используем синхронный httpx клиент для больших файлов
|
connect=10.0,
|
||||||
import httpx as httpx_sync
|
read=120.0,
|
||||||
upload_timeout_config = httpx_sync.Timeout(
|
write=write_timeout, # Динамический таймаут на запись
|
||||||
connect=10.0,
|
pool=10.0
|
||||||
read=120.0,
|
)
|
||||||
write=write_timeout, # Динамический таймаут на запись
|
|
||||||
pool=10.0
|
try:
|
||||||
)
|
|
||||||
|
|
||||||
with httpx_sync.Client(
|
with httpx_sync.Client(
|
||||||
http2=False,
|
http2=False,
|
||||||
timeout=upload_timeout_config,
|
timeout=upload_timeout_config,
|
||||||
@@ -298,38 +297,21 @@ async def publish_to_tg(vk_post_id):
|
|||||||
}
|
}
|
||||||
|
|
||||||
photo_response = sync_client.post(send_photo_url, files=files, data=data)
|
photo_response = sync_client.post(send_photo_url, files=files, data=data)
|
||||||
else:
|
except (httpx_sync.TimeoutException, httpx_sync.WriteTimeout, httpx_sync.ReadTimeout) as sync_timeout:
|
||||||
# Для маленьких файлов используем асинхронный клиент
|
# Обработка таймаутов от синхронного клиента
|
||||||
# Создаем клиент с увеличенным таймаутом на запись для больших файлов
|
timeout_type = type(sync_timeout).__name__
|
||||||
upload_timeout_config = httpx.Timeout(
|
request_duration = time.time() - request_start_time
|
||||||
connect=10.0,
|
logger.error(f"ТАЙМАУТ ({timeout_type}) при отправке изображения (синхронный клиент) для записи VK ID {vk_post_id}")
|
||||||
read=120.0,
|
logger.error(f"Время до таймаута: {request_duration:.2f} секунд")
|
||||||
write=write_timeout, # Динамический таймаут на запись
|
logger.error(f"Тип исключения: {timeout_type}")
|
||||||
pool=10.0
|
logger.error(f"Сообщение об ошибке: {str(sync_timeout)}")
|
||||||
)
|
logger.error(f"Полная информация об исключении: {repr(sync_timeout)}")
|
||||||
upload_client = httpx.AsyncClient(
|
logger.error(f"URL изображения: {image_url}")
|
||||||
http2=False,
|
logger.error(f"Размер файла: {file_size_mb:.2f} МБ")
|
||||||
timeout=upload_timeout_config,
|
if hasattr(sync_timeout, 'request'):
|
||||||
follow_redirects=True
|
logger.error(f"Запрос, вызвавший таймаут: {sync_timeout.request.method} {sync_timeout.request.url if hasattr(sync_timeout.request, 'url') else 'N/A'}")
|
||||||
)
|
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
||||||
|
raise # Пробрасываем таймаут наверх
|
||||||
try:
|
|
||||||
# Отправляем изображение как файл через multipart/form-data
|
|
||||||
# Создаем BytesIO объект для файла
|
|
||||||
image_file = io.BytesIO(image_data)
|
|
||||||
files = {
|
|
||||||
'photo': ('image.jpg', image_file, 'image/jpeg')
|
|
||||||
}
|
|
||||||
data = {
|
|
||||||
'chat_id': CHANNEL_ID,
|
|
||||||
'caption': text,
|
|
||||||
'parse_mode': 'HTML',
|
|
||||||
'disable_notification': str(PUBLISH_SILENTLY).lower()
|
|
||||||
}
|
|
||||||
|
|
||||||
photo_response = await upload_client.post(send_photo_url, files=files, data=data)
|
|
||||||
finally:
|
|
||||||
await upload_client.aclose()
|
|
||||||
|
|
||||||
request_duration = time.time() - request_start_time
|
request_duration = time.time() - request_start_time
|
||||||
logger.info(f"Запрос отправки фото завершен за {request_duration:.2f} секунд")
|
logger.info(f"Запрос отправки фото завершен за {request_duration:.2f} секунд")
|
||||||
@@ -362,19 +344,33 @@ async def publish_to_tg(vk_post_id):
|
|||||||
raise Exception(f"HTTP {photo_response.status_code}: {photo_response.text}")
|
raise Exception(f"HTTP {photo_response.status_code}: {photo_response.text}")
|
||||||
except RetryAfterException:
|
except RetryAfterException:
|
||||||
raise
|
raise
|
||||||
except (httpx.TimeoutException, httpx.WriteTimeout, httpx.ReadTimeout) as e:
|
except Exception as e:
|
||||||
timeout_type = type(e).__name__
|
# Проверяем, является ли это таймаутом (может быть от синхронного или асинхронного клиента)
|
||||||
logger.error(f"ТАЙМАУТ ({timeout_type}) при отправке изображения для записи VK ID {vk_post_id}")
|
import httpx as httpx_sync
|
||||||
logger.error(f"Тип исключения: {timeout_type}")
|
is_timeout = (
|
||||||
logger.error(f"Сообщение об ошибке: {str(e)}")
|
isinstance(e, (httpx.TimeoutException, httpx.WriteTimeout, httpx.ReadTimeout)) or
|
||||||
logger.error(f"Полная информация об исключении: {repr(e)}")
|
isinstance(e, (httpx_sync.TimeoutException, httpx_sync.WriteTimeout, httpx_sync.ReadTimeout))
|
||||||
if hasattr(e, 'request'):
|
)
|
||||||
logger.error(f"Запрос, вызвавший таймаут: {e.request.method} {e.request.url if hasattr(e.request, 'url') else 'N/A'}")
|
|
||||||
# Для WriteTimeout логируем размер файла
|
if is_timeout:
|
||||||
if isinstance(e, httpx.WriteTimeout) and image_data is not None:
|
timeout_type = type(e).__name__
|
||||||
logger.error(f"Размер файла, вызвавшего таймаут записи: {len(image_data) / (1024 * 1024):.2f} МБ")
|
request_duration = time.time() - request_start_time if 'request_start_time' in locals() else 0
|
||||||
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
logger.error(f"ТАЙМАУТ ({timeout_type}) при отправке изображения для записи VK ID {vk_post_id}")
|
||||||
raise # Пробрасываем таймаут наверх
|
if request_duration > 0:
|
||||||
|
logger.error(f"Время до таймаута: {request_duration:.2f} секунд")
|
||||||
|
logger.error(f"Тип исключения: {timeout_type}")
|
||||||
|
logger.error(f"Сообщение об ошибке: {str(e)}")
|
||||||
|
logger.error(f"Полная информация об исключении: {repr(e)}")
|
||||||
|
logger.error(f"URL изображения: {image_url}")
|
||||||
|
if image_data is not None:
|
||||||
|
logger.error(f"Размер файла: {len(image_data) / (1024 * 1024):.2f} МБ")
|
||||||
|
if hasattr(e, 'request'):
|
||||||
|
logger.error(f"Запрос, вызвавший таймаут: {e.request.method} {e.request.url if hasattr(e.request, 'url') else 'N/A'}")
|
||||||
|
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
||||||
|
raise # Пробрасываем таймаут наверх
|
||||||
|
|
||||||
|
# Если это не таймаут, пробрасываем дальше для обработки как обычная ошибка
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Не удалось отправить изображение для записи VK ID {vk_post_id}: {e}. Отправляем текстовое сообщение.")
|
logger.warning(f"Не удалось отправить изображение для записи VK ID {vk_post_id}: {e}. Отправляем текстовое сообщение.")
|
||||||
message_has_image = False # Отправляем текстовое сообщение вместо изображения
|
message_has_image = False # Отправляем текстовое сообщение вместо изображения
|
||||||
|
|||||||
Reference in New Issue
Block a user