С выходом платформы 1С версии 8.3.8 разработчики столкнулись с серьезным ограничением: при завершении работы системы (в обработчике ПередЗавершениемРаботыСистемы) стали недоступны синхронные серверные вызовы. Это обусловлено переходом платформы на асинхронную модель работы и требованиями современных веб-браузеров, которые блокируют любые попытки страницы «задержать» пользователя при закрытии вкладки. Однако на практике часто возникает необходимость записать данные в Журнал регистрации, сохранить состояние объектов или отправить уведомление на сервер именно в момент выхода. Рассмотрим подробнее, как обойти это ограничение, проанализируем различные сценарии и разберем проверенные способы решения задачи.
Разберем ситуацию: начиная с 8.3.8, 1С стремится к полной поддержке Web-клиента. В браузерах событие закрытия страницы жестко ограничено по времени и возможностям. Если платформа позволит выполнять длительные серверные вызовы в этот момент, это приведет к зависанию интерфейса или некорректному поведению приложения. В связи с этим попытка вызвать серверную функцию в ПередЗавершениемРаботыСистемы приводит к ошибке или игнорированию вызова. Выясним причину, по которой стандартные методы Сообщить или прямые вызовы процедур &НаСервере перестают работать в этом контексте — платформа просто блокирует поток выполнения, чтобы гарантировать закрытие сеанса.
Проанализируем самый популярный и надежный способ — использование обработчика ожидания. Суть метода заключается в том, чтобы отменить текущее завершение работы, выполнить необходимые действия на сервере в отдельном потоке и затем инициировать закрытие системы заново, но уже с флагом, разрешающим выход. Посмотрим на пример реализации в модуле управляемого приложения.
Сначала объявим переменную в разделе описания переменных модуля:
Перем РазрешитьЗавершениеРаботы;
Далее реализуем логику в обработчике события:
Процедура ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения)
Если РазрешитьЗавершениеРаботы = Истина Тогда
Возврат; // Выход разрешен, ничего не делаем
КонецЕсли;
// Если мы здесь, значит это первая попытка выхода
Отказ = Истина; // Блокируем стандартный выход
РазрешитьЗавершениеРаботы = Истина;
// Подключаем обработчик, в котором сделаем все дела
ПодключитьОбработчикОжидания("ВыполнитьСерверныеДействияПередВыходом", 0.1, Истина);
КонецПроцедуры
И, наконец, сам обработчик ожидания, который должен быть экспортным:
Процедура ВыполнитьСерверныеДействияПередВыходом() Экспорт
// Здесь мы можем свободно вызывать сервер
ЗаписатьСтатистикуНаСервере();
// Теперь инициируем завершение работы повторно
// Параметр Ложь означает, что пользователю не нужно повторно подтверждать выход
ЗавершитьРаботуСистемы(Ложь);
КонецПроцедуры
Важный нюанс: этот метод отлично работает в тонком клиенте, но может давать осечки в веб-клиенте, если пользователь закрывает вкладку крестиком. Однако для штатного выхода через меню или кнопку «Закрыть» это решение является эталонным.
Выясним еще одну интересную особенность: иногда объект HTTPСоединение позволяет «проскочить» ограничения платформы, так как он работает напрямую с сетевыми протоколами. Если в вашей системе развернуты HTTP-сервисы, вы можете отправить короткое сообщение о завершении сеанса прямо из клиента. Рассмотрим пример кода:
Процедура ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения)
// Пытаемся отправить информацию через легкий HTTP-запрос
Попытка
HTTP = Новый HTTPСоединение("ваш_сервер", 80);
ЗапросHTTP = Новый HTTPЗапрос("api/session/close?user=" + ИмяПользователя());
HTTP.ОтправитьДляОбработки(ЗапросHTTP);
Исключение
// Игнорируем ошибки, чтобы не блокировать выход
КонецПопытки;
КонецПроцедуры
Этот метод хорош тем, что он минимально нагружает систему в момент закрытия и часто успевает отработать даже в условиях ограниченного времени жизни клиентского потока.
Если вы работаете с файловой информационной базой, можно применить подход с записью во внешний файл. Это позволяет сохранить нужную информацию (например, для последующего анализа причин завершения) без обращения к серверному контексту базы данных. Разберем пример функции, предложенной участниками сообщества:
Функция ЗаписатьИнформациюВФайл(Информация)
СтрокаСоединения = СтрокаСоединенияИнформационнойБазы();
// Извлекаем путь к базе из строки соединения File="..."
ПутьКБазе = Сред(СтрокаСоединения, 7, СтрДлина(СтрокаСоединения) - 8);
ИмяФайла = ПутьКБазе + "\exit_log.txt";
Файл = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8, , Истина); // Дозапись
Файл.ЗаписатьСтроку(ТекущаяДата() + ": " + Информация);
Файл.Закрыть();
КонецФункции
Эту функцию можно вызывать в ПередЗавершениемРаботыСистемы. Поскольку работа с локальными файлами (при наличии прав) разрешена на клиенте, это действие выполнится успешно.
Рассмотрим ситуацию, когда вам нужно выполнить код на сервере независимо от того, как именно закрылось клиентское приложение (вылетело по ошибке, закрыли вкладку или пропал интернет) — для этого есть обработка принудительного завершения сеансов пользователей 1С. В этом случае использование клиентских обработчиков не поможет. Проанализируем возможности Модуля сеанса.
В нем существует обработчик ПриЗавершенииСеанса. Это «чистый» серверный контекст. Когда кластер серверов 1С понимает, что соединение с клиентом разорвано, он запускает эту процедуру. Здесь можно писать в Журнал регистрации, удалять временные записи в таблицах или выполнять другие регламентные действия. Главный плюс: этот код выполнится в 100% случаев завершения сеанса.
Проанализируем ситуацию, с которой часто сталкиваются новички (сообщение №28 на форуме). Попытка вызвать форму или вывести Сообщить в момент закрытия формы, когда параметр ЗавершениеРаботы равен Истина, обречена на провал. Платформа в этом режиме переходит в состояние «терминации», и любые попытки взаимодействия с интерфейсом блокируются.
Запомним правила:
Сообщить в финальных стадиях закрытия — пользователь их не увидит.ТекстПредупреждения. Если он заполнен, платформа сама покажет стандартное окно с кнопками «Да/Нет».ПодключитьОбработчикОжидания, чтобы разорвать связь с блокирующим событием закрытия.Подводя итог, можно сказать, что хотя 1С и ограничила прямые вызовы сервера, архитектурно правильный подход через обработчик ожидания или использование серверных событий модуля сеанса позволяет решить 99% практических задач. Мы вместе разобрали наиболее эффективные методики, которые помогут вам сохранить стабильность системы и обеспечить выполнение необходимых алгоритмов при выходе пользователей.