From 9ca2bd17424dd0e22b270eb5c3a3972822de4f55 Mon Sep 17 00:00:00 2001 From: jze9 Date: Thu, 23 Jul 2026 19:16:13 +0500 Subject: [PATCH] =?UTF-8?q?fix(notifier):=20=D0=BC=D0=B0=D0=BF=D0=BF=D0=B8?= =?UTF-8?q?=D0=BD=D0=B3=20input=5Fdata=20=D0=B2=20=D0=BC=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B8=20Task=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=B2=D0=B5?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=BE=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B2=D0=B5=D1=80=D1=88=D0=B5=D0=BD=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit send_task_done падал с AttributeError: минимальная модель Task в notifier не мапила колонку input_data (она есть в БД и в полной модели API), а _build_summary читал task.input_data для search/plagiarism. Задача уходила в бесконечные ретраи. Добавлен маппинг колонки + защита от NULL. Co-Authored-By: Claude Opus 4.8 --- services/worker-notifier/app/models/__init__.py | 1 + services/worker-notifier/app/tasks/notify.py | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/services/worker-notifier/app/models/__init__.py b/services/worker-notifier/app/models/__init__.py index bf916d4..63382d1 100644 --- a/services/worker-notifier/app/models/__init__.py +++ b/services/worker-notifier/app/models/__init__.py @@ -25,6 +25,7 @@ class Task(Base): user_id: Mapped[int] = mapped_column(ForeignKey("users.id")) type: Mapped[str] = mapped_column(String(20)) status: Mapped[str] = mapped_column(String(20)) + input_data: Mapped[dict | None] = mapped_column(JSON, nullable=True) result: Mapped[dict | None] = mapped_column(JSON, nullable=True) error: Mapped[str | None] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column(server_default=func.now()) diff --git a/services/worker-notifier/app/tasks/notify.py b/services/worker-notifier/app/tasks/notify.py index 1d3a56d..c664426 100644 --- a/services/worker-notifier/app/tasks/notify.py +++ b/services/worker-notifier/app/tasks/notify.py @@ -68,10 +68,11 @@ def send_task_done(self, task_id: str) -> dict: def _build_summary(task) -> str: """Сформировать краткое описание результата для email.""" result = task.result or {} + input_data = task.input_data or {} if task.type == "search": count = len(result.get("sources", [])) - query = task.input_data.get("query", "") + query = input_data.get("query", "") return ( f'Найдено {count} источников по запросу "{query[:80]}".' f' Откройте результат, чтобы просмотреть список с ГОСТ-цитатами.' @@ -81,7 +82,7 @@ def _build_summary(task) -> str: similarity = result.get("overall_similarity", 0) total = result.get("total_fragments", 0) flagged = result.get("flagged_fragments", 0) - filename = task.input_data.get("filename", "") + filename = input_data.get("filename", "") color = "#dc2626" if similarity > 30 else "#d97706" if similarity > 10 else "#16a34a" label = "Высокий" if similarity > 30 else "Средний" if similarity > 10 else "Низкий"