В процессе промышленной эксплуатации систем на платформе 1С:Предприятие регулярно возникают ситуации, когда регламентные или фоновые процессы перестают отвечать. Типичный пример — рассылка печатных форм, счетов и заказов клиентам, когда при обращении к внешнему почтовому сервису сокет зависает в режиме ожидания ответа. Если администратор не отслеживает стандартную консоль заданий непрерывно, о проблеме становится известно слишком поздно. Разберем, как программно выявлять длительно выполняющиеся фоновые задания, устранять причины их зависания и организовывать систему оперативного оповещения.
Прежде чем выстраивать архитектуру мониторинга, проанализируем основные факторы, приводящие к «вечному» выполнению фоновых задач:
ИнтернетПочта отсутствие явно заданного времени ожидания приводит к тому, что при разрыве TCP-сессии без флагов RST/FIN поток переходит в бесконечное ожидание.rphost.Рассмотрим, как предотвратить зависание задач, связанных с отправкой почты. Для этого обязательно укажем явный таймаут подключения в свойствах почтового профиля и изолируем вызовы в блок обработки ошибок.
Посмотрим на пример правильной инициализации почтового профиля:
Профиль = Новый ИнтернетПочтовыйПрофиль;
Профиль.АдресСервераSMTP = "smtp.example.com";
Профиль.ПортSMTP = 25;
Профиль.ПользовательSMTP = "robot@example.com";
Профиль.ПарольSMTP = "SecurePassword";
// Задаем явное ограничение времени ожидания ответа сервера в секундах
Профиль.ВремяОжидания = 30;
Почта = Новый ИнтернетПочта;
Попытка
Почта.Подключиться(Профиль, ПротоколИнтернетПочты.SMTP);
Почта.Послать(Письмо);
Исключение
ЗаписьЖурналаРегистрации("ОтправкаПочты", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
Если Почта.Подключена() Тогда
Почта.Отключиться();
КонецЕсли;
Установка свойства ВремяОжидания гарантирует, что при сетевом сбое соединение не зависнет на часы, а аварийно завершится по истечении 30 секунд, породив штатное исключение.
Разберем, как встроенными средствами платформы получить список всех выполняющихся в данный момент заданий и вычислить те, время работы которых превысило допустимый лимит (например, 30 минут).
Для программного доступа к задачам используется метод ФоновыеЗадания.ПолучитьФоновыеЗадания() (или обращение к МенеджерФоновыхЗаданий). Метод принимает структуру отбора со следующими допустимыми полями: УникальныйИдентификатор, Ключ, Состояние, Начало, Конец, Наименование, ИмяМетода, РегламентноеЗадание.
Посмотрим на пример функции, которая анализирует запущенные задания:
Функция ПолучитьСписокЗависшихЗаданий(ПорогМинут = 30) Экспорт
Отбор = Новый Структура;
Отбор.Вставить("Состояние", СостояниеФоновогоЗадания.Активно);
// Получаем массив объектов ФоновоеЗадание
МассивЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор);
ЗависшиеЗадания = Новый Массив;
ТекущееВремя = ТекущаяДатаСеанса();
ПорогВСекундах = ПорогМинут * 60;
Для Каждого Задание Из МассивЗаданий Цикл
// Проверяем, заполнена ли дата начала и превышен ли лимит времени
Если ЗначениеЗаполнено(Задание.Начало) Тогда
Длительность = ТекущееВремя - Задание.Начало;
Если Длительность > ПорогВСекундах Тогда
ОписаниеПроблемы = Новый Структура;
ОписаниеПроблемы.Вставить("Имя", Задание.Наименование);
ОписаниеПроблемы.Вставить("Метод", Задание.ИмяМетода);
ОписаниеПроблемы.Вставить("Начало", Задание.Начало);
ОписаниеПроблемы.Вставить("ДлительностьМинут", Окр(Длительность / 60));
ОписаниеПроблемы.Вставить("Идентификатор", Строка(Задание.УникальныйИдентификатор));
ЗависшиеЗадания.Добавить(ОписаниеПроблемы);
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат ЗависшиеЗадания;
КонецФункции
Важное ограничение: вызов данного метода доступен только на стороне сервера администраторам кластера либо пользователю, инициировавшему запуск конкретных фоновых потоков.
Если фоновое задание по отправке почты зависло из-за проблем с почтовым сервером, отправлять уведомления администраторам через ИнтернетПочта не имеет смысла. Оптимальный канал доставки алертов — мессенджеры (например, Telegram).
Разберем по шагам, как отправить аварийное сообщение администратору через HTTP-запрос к API мессенджера:
Процедура ОтправитьОповещениеВМессенджер(ТекстСообщения, ТокенБота, ИдентификаторЧата) Экспорт
Сервер = "api.telegram.org";
Ресурс = "/bot" + ТокенБота + "/sendMessage";
ПараметрыЗапроса = "chat_id=" + ИдентификаторЧата + "&text=" + КодироватьСтроку(ТекстСообщения, СпособКодированияСтроки.КодировкаURL);
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
Соединение = Новый HTTPСоединение(Сервер, 443,,,, 15, ЗащищенноеСоединение);
Запрос = Новый HTTPЗапрос(Ресурс);
Запрос.УстановитьТелоИзСтроки(ПараметрыЗапроса, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
Запрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
Попытка
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Исключение
ЗаписьЖурналаРегистрации("МониторингФЗ", УровеньЖурналаРегистрации.Ошибка,,, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Необходимо учитывать фундаментальное ограничение встроенного контроля: если рабочий процесс rphost или весь кластер 1С исчерпал лимиты ресурсов, очередное контролирующее фоновое задание внутри той же информационной базы попросту не запустится. Кроме того, вызов метода ФоновоеЗадание.Отменить() не прерывает физический поток операционной системы, если он заблокирован на уровне ядра при чтении сокета.
Для надежного промышленного контроля рекомендуется выносить мониторинг во внешние системы:
CALL с фильтром по длительности (Duration) для фиксации серверных вызовов, превышающих пороговые значения, с последующим парсингом логов сторонними анализаторами.