diff --git a/backend/app/services/host_silence_scan.py b/backend/app/services/host_silence_scan.py index c104e62..d5e9c32 100644 --- a/backend/app/services/host_silence_scan.py +++ b/backend/app/services/host_silence_scan.py @@ -114,6 +114,13 @@ def dispatch_host_silence_notifications(db: Session, results: list[HostSilenceSc for item in results: if not item.created: continue - notify_problem(item.problem, event=None, db=db) - sent += 1 + try: + notify_problem(item.problem, event=None, db=db) + sent += 1 + except Exception: + logger.exception( + "host_silence notify failed host=%s problem_id=%s", + item.hostname, + item.problem.id, + ) return sent diff --git a/backend/app/services/telegram_templates.py b/backend/app/services/telegram_templates.py index 9e4e2fb..0537453 100644 --- a/backend/app/services/telegram_templates.py +++ b/backend/app/services/telegram_templates.py @@ -543,8 +543,6 @@ def format_problem_telegram_html(problem: Problem, event: Event | None = None) - msg += f"\n{html_escape(problem.title)}\n{html_escape(problem.summary)}" if event is not None: msg += f"\n\nТриггер: {html_escape(event.type)} ({html_escape(event.severity)})" - elif problem.rule_id == "rule:host_silence": - msg += "\n\nТриггер: периодическая проверка SAC (host_silence scan)" if event.type in ( "rdp.login.success", "rdp.login.failed", @@ -557,4 +555,6 @@ def format_problem_telegram_html(problem: Problem, event: Event | None = None) - "smb.admin_share.access", ): msg += "\n" + _format_event_body_html(event) + elif problem.rule_id == "rule:host_silence": + msg += "\n\nТриггер: периодическая проверка SAC (host_silence scan)" return append_notification_source_html(msg, generated_by="sac") diff --git a/backend/tests/test_telegram_templates.py b/backend/tests/test_telegram_templates.py index e17845a..342c35f 100644 --- a/backend/tests/test_telegram_templates.py +++ b/backend/tests/test_telegram_templates.py @@ -326,3 +326,32 @@ def test_agent_inventory_hardware_change_template(): assert "железо" in text.lower() or "Изменилось" in text assert "memory_gb" in text assert "32" in text + + +def test_format_problem_host_silence_scan_without_event(): + from app.models import Host, Problem + from app.services.problem_rules import RULE_HOST_SILENCE + from app.services.telegram_templates import format_problem_telegram_html + + host = Host( + hostname="YURKOV-PC", + os_family="windows", + product="rdp-login-monitor", + last_seen_at=datetime(2026, 6, 11, 9, 0, tzinfo=timezone.utc), + ) + problem = Problem( + host_id=1, + host=host, + title="Host silence: YURKOV-PC", + summary="Нет свежего agent.heartbeat более 300 мин", + severity="high", + status="open", + rule_id=RULE_HOST_SILENCE, + fingerprint="fp-silence", + event_count=0, + last_seen_at=datetime(2026, 6, 11, 9, 0, tzinfo=timezone.utc), + ) + text = format_problem_telegram_html(problem, event=None) + assert "периодическая проверка SAC" in text + assert "host_silence scan" in text + assert "YURKOV-PC" in text or "UNMS" not in text # host label uses hostname