This commit is contained in:
+22
-2
@@ -1032,11 +1032,31 @@ def api_publish_post(post_id):
|
|||||||
# Функция для запуска в отдельном потоке
|
# Функция для запуска в отдельном потоке
|
||||||
def run_async_func():
|
def run_async_func():
|
||||||
try:
|
try:
|
||||||
|
# Создаем новый event loop для этого потока
|
||||||
|
# Это важно при работе с gunicorn, который может иметь свой event loop
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
result = loop.run_until_complete(publish_to_tg(post['vk_post_id']))
|
try:
|
||||||
return result
|
result = loop.run_until_complete(publish_to_tg(post['vk_post_id']))
|
||||||
|
return result
|
||||||
|
finally:
|
||||||
|
# Закрываем event loop после завершения
|
||||||
|
# Это важно для предотвращения утечек ресурсов
|
||||||
|
try:
|
||||||
|
# Отменяем все незавершенные задачи
|
||||||
|
pending = asyncio.all_tasks(loop)
|
||||||
|
for task in pending:
|
||||||
|
task.cancel()
|
||||||
|
# Ждем завершения отмененных задач
|
||||||
|
if pending:
|
||||||
|
loop.run_until_complete(asyncio.gather(*pending, return_exceptions=True))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
loop.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
log_event(f"Ошибка в run_async_func: {str(e)}\n{traceback.format_exc()}")
|
||||||
return e
|
return e
|
||||||
|
|
||||||
# Создаем очередь для передачи результата
|
# Создаем очередь для передачи результата
|
||||||
|
|||||||
+35
-1
@@ -135,9 +135,16 @@ async def publish_to_tg(vk_post_id):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# Создаем httpx клиент с отключенным HTTP/2
|
# Создаем httpx клиент с отключенным HTTP/2
|
||||||
|
# Используем более детальные таймауты: connect, read, write, pool
|
||||||
|
timeout_config = httpx.Timeout(
|
||||||
|
connect=10.0, # Таймаут на подключение
|
||||||
|
read=60.0, # Таймаут на чтение (увеличен для больших изображений)
|
||||||
|
write=30.0, # Таймаут на запись
|
||||||
|
pool=10.0 # Таймаут на получение соединения из пула
|
||||||
|
)
|
||||||
httpx_client = httpx.AsyncClient(
|
httpx_client = httpx.AsyncClient(
|
||||||
http2=False,
|
http2=False,
|
||||||
timeout=20.0,
|
timeout=timeout_config,
|
||||||
follow_redirects=True
|
follow_redirects=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -199,6 +206,12 @@ async def publish_to_tg(vk_post_id):
|
|||||||
|
|
||||||
if has_image and not is_org_message:
|
if has_image and not is_org_message:
|
||||||
try:
|
try:
|
||||||
|
# Логируем информацию об изображении перед отправкой
|
||||||
|
logger.info(f"Отправка изображения для записи VK ID {vk_post_id}")
|
||||||
|
logger.info(f"URL изображения: {image_url}")
|
||||||
|
logger.info(f"Длина URL изображения: {len(image_url)} символов")
|
||||||
|
logger.info(f"Длина подписи: {len(text)} символов")
|
||||||
|
|
||||||
photo_payload = {
|
photo_payload = {
|
||||||
'chat_id': CHANNEL_ID,
|
'chat_id': CHANNEL_ID,
|
||||||
'photo': image_url,
|
'photo': image_url,
|
||||||
@@ -206,15 +219,29 @@ async def publish_to_tg(vk_post_id):
|
|||||||
'parse_mode': 'HTML',
|
'parse_mode': 'HTML',
|
||||||
'disable_notification': PUBLISH_SILENTLY
|
'disable_notification': PUBLISH_SILENTLY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Логируем время начала запроса
|
||||||
|
request_start_time = time.time()
|
||||||
|
logger.info(f"Начало запроса отправки фото в {datetime.now(timezone.utc).isoformat()}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
photo_response = await httpx_client.post(send_photo_url, json=photo_payload)
|
photo_response = await httpx_client.post(send_photo_url, json=photo_payload)
|
||||||
|
request_duration = time.time() - request_start_time
|
||||||
|
logger.info(f"Запрос отправки фото завершен за {request_duration:.2f} секунд")
|
||||||
except httpx.TimeoutException as e:
|
except httpx.TimeoutException as e:
|
||||||
|
request_duration = time.time() - request_start_time
|
||||||
logger.error(f"ТАЙМАУТ при отправке фото для записи VK ID {vk_post_id}")
|
logger.error(f"ТАЙМАУТ при отправке фото для записи VK ID {vk_post_id}")
|
||||||
|
logger.error(f"Время до таймаута: {request_duration:.2f} секунд")
|
||||||
logger.error(f"Тип исключения: {type(e).__name__}")
|
logger.error(f"Тип исключения: {type(e).__name__}")
|
||||||
logger.error(f"Сообщение об ошибке: {str(e)}")
|
logger.error(f"Сообщение об ошибке: {str(e)}")
|
||||||
logger.error(f"Полная информация об исключении: {repr(e)}")
|
logger.error(f"Полная информация об исключении: {repr(e)}")
|
||||||
|
logger.error(f"URL изображения: {image_url}")
|
||||||
|
logger.error(f"Длина URL изображения: {len(image_url)} символов")
|
||||||
if hasattr(e, 'request'):
|
if hasattr(e, 'request'):
|
||||||
logger.error(f"Запрос, вызвавший таймаут: {e.request.method} {e.request.url if hasattr(e.request, 'url') else 'N/A'}")
|
logger.error(f"Запрос, вызвавший таймаут: {e.request.method} {e.request.url if hasattr(e.request, 'url') else 'N/A'}")
|
||||||
|
# Пытаемся получить информацию о таймауте из исключения
|
||||||
|
if hasattr(e, 'timeout'):
|
||||||
|
logger.error(f"Настройки таймаута: {e.timeout}")
|
||||||
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
||||||
raise # Пробрасываем таймаут наверх
|
raise # Пробрасываем таймаут наверх
|
||||||
|
|
||||||
@@ -599,6 +626,13 @@ async def publish_to_tg(vk_post_id):
|
|||||||
logger.error(f"Полная информация об исключении: {repr(e)}")
|
logger.error(f"Полная информация об исключении: {repr(e)}")
|
||||||
if hasattr(e, 'request'):
|
if hasattr(e, 'request'):
|
||||||
logger.error(f"Запрос, вызвавший таймаут: {e.request.method} {e.request.url if hasattr(e.request, 'url') else 'N/A'}")
|
logger.error(f"Запрос, вызвавший таймаут: {e.request.method} {e.request.url if hasattr(e.request, 'url') else 'N/A'}")
|
||||||
|
# Пытаемся получить информацию о таймауте из исключения
|
||||||
|
if hasattr(e, 'timeout'):
|
||||||
|
logger.error(f"Настройки таймаута: {e.timeout}")
|
||||||
|
# Проверяем, запущены ли мы из gunicorn
|
||||||
|
import sys
|
||||||
|
if 'gunicorn' in sys.modules:
|
||||||
|
logger.warning("Обнаружен gunicorn - возможен конфликт с event loop при запуске асинхронного кода в отдельном потоке")
|
||||||
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
|
||||||
# Убеждаемся, что БД не обновляется при таймауте
|
# Убеждаемся, что БД не обновляется при таймауте
|
||||||
return False
|
return False
|
||||||
|
|||||||
Reference in New Issue
Block a user