Пытаемся угомонить превьюшки
All checks were successful
Deploy MES Core / deploy (push) Successful in 10s

This commit is contained in:
2026-04-03 01:58:23 +03:00
parent b76ce4913f
commit 1fe05d41f6
5 changed files with 141 additions and 39 deletions

View File

@@ -1,5 +1,7 @@
import logging
import multiprocessing
import os
import sys
from django.core.management.base import BaseCommand
from django.db import close_old_connections
@@ -56,11 +58,25 @@ class Command(BaseCommand):
job.started_at = timezone.now()
job.finished_at = None
job.last_message = ""
job.save(update_fields=["status", "started_at", "finished_at", "last_message"])
try:
job.pid = os.getpid()
job.save(update_fields=["status", "started_at", "finished_at", "last_message", "pid"])
except Exception:
job.save(update_fields=["status", "started_at", "finished_at", "last_message"])
logger = logging.getLogger('dxf_preview_job')
if not logger.handlers:
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s', '%Y-%m-%d %H:%M:%S'))
logger.addHandler(handler)
logger.setLevel(logging.INFO)
logger.info('start job=%s pid=%s', job_id, os.getpid())
# Берём настройки таймаута из БД.
settings, _ = DxfPreviewSettings.objects.get_or_create(pk=1)
per_task_timeout = int(getattr(settings, 'per_task_timeout_sec', 45) or 45)
per_task_timeout = max(10, min(50, per_task_timeout))
deal_statuses = ["lead", "work"]
qs = ProductionTask.objects.select_related("deal").filter(deal__status__in=deal_statuses)
@@ -79,9 +95,7 @@ class Command(BaseCommand):
skipped = 0
errors = 0
# Таймаут обработки одной детали (сек).
# Если конкретный DXF «залип» — задача не должна блокироваться навсегда.
per_task_timeout = 45
logger.info('per_task_timeout=%ss', per_task_timeout)
try:
for task in qs.iterator(chunk_size=50):
@@ -106,7 +120,8 @@ class Command(BaseCommand):
return
# Обрабатываем одну деталь в отдельном процессе и ждём не больше per_task_timeout.
close_old_connections()
# Важно: НЕ вызываем close_old_connections() внутри qs.iterator(), иначе Django может закрыть курсор,
# и итерация по QuerySet упадёт с ошибкой "cursor already closed".
q: multiprocessing.Queue = multiprocessing.Queue(maxsize=1)
p = multiprocessing.Process(target=_run_one_task_preview, args=(task.id, q))
p.start()
@@ -137,8 +152,7 @@ class Command(BaseCommand):
skipped += 1
else:
errors += 1
close_old_connections()
logger.error('error task=%s name=%s deal=%s: %s', task.id, task.drawing_name, task.deal.number, payload)
DxfPreviewJob.objects.filter(pk=job_id).update(
processed=processed,
@@ -153,10 +167,11 @@ class Command(BaseCommand):
last_message=f"Готово. Обновлены: {updated}. Пропущено: {skipped}. Ошибок: {errors}.",
)
except Exception:
logger.exception('fatal error')
DxfPreviewJob.objects.filter(pk=job_id).update(
status="failed",
finished_at=timezone.now(),
last_message="Задача завершилась с ошибкой (см. логи процесса).",
last_message="Задача завершилась с ошибкой (см. лог на странице обслуживания).",
)
finally:
close_old_connections()