[ВОЛК] оптимизируем работу с event_loop
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-01-10 14:54:31 +03:00
parent bccf3e7717
commit 8556b1f508
2 changed files with 57 additions and 3 deletions
+20
View File
@@ -1032,11 +1032,31 @@ def api_publish_post(post_id):
# Функция для запуска в отдельном потоке
def run_async_func():
try:
# Создаем новый event loop для этого потока
# Это важно при работе с gunicorn, который может иметь свой event loop
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
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:
import traceback
log_event(f"Ошибка в run_async_func: {str(e)}\n{traceback.format_exc()}")
return e
# Создаем очередь для передачи результата
+35 -1
View File
@@ -135,9 +135,16 @@ async def publish_to_tg(vk_post_id):
return False
# Создаем 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(
http2=False,
timeout=20.0,
timeout=timeout_config,
follow_redirects=True
)
@@ -199,6 +206,12 @@ async def publish_to_tg(vk_post_id):
if has_image and not is_org_message:
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 = {
'chat_id': CHANNEL_ID,
'photo': image_url,
@@ -206,15 +219,29 @@ async def publish_to_tg(vk_post_id):
'parse_mode': 'HTML',
'disable_notification': PUBLISH_SILENTLY
}
# Логируем время начала запроса
request_start_time = time.time()
logger.info(f"Начало запроса отправки фото в {datetime.now(timezone.utc).isoformat()}")
try:
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:
request_duration = time.time() - request_start_time
logger.error(f"ТАЙМАУТ при отправке фото для записи VK ID {vk_post_id}")
logger.error(f"Время до таймаута: {request_duration:.2f} секунд")
logger.error(f"Тип исключения: {type(e).__name__}")
logger.error(f"Сообщение об ошибке: {str(e)}")
logger.error(f"Полная информация об исключении: {repr(e)}")
logger.error(f"URL изображения: {image_url}")
logger.error(f"Длина URL изображения: {len(image_url)} символов")
if hasattr(e, 'request'):
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()}")
raise # Пробрасываем таймаут наверх
@@ -599,6 +626,13 @@ async def publish_to_tg(vk_post_id):
logger.error(f"Полная информация об исключении: {repr(e)}")
if hasattr(e, 'request'):
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()}")
# Убеждаемся, что БД не обновляется при таймауте
return False