Как вызвать серверный метод перед завершением работы системы в 1С 8.3

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработчики прикладных решений на платформе «1С:Предприятие 8.3» с управляемым интерфейсом часто сталкиваются с задачей выполнения обязательных действий перед выходом пользователя из базы. Типичные примеры — отправка служебных логов, выгрузка данных в распределенную информационную базу (РИБ), очистка временных таблиц или проверка блокировок. Однако попытка вызвать серверную функцию непосредственно из предопределенных событий модуля управляемого приложения приводит к ошибке выполнения.

Разберем причины такого поведения платформы и подробно рассмотрим надежные архитектурные паттерны решения этой задачи.

Причина ограничения на серверные вызовы при закрытии

Начиная с версии платформы 8.3.8 (и при отключенном режиме совместимости с версией 8.3.7), разработчики фирмы «1С» кардинально изменили концепцию завершения работы клиентского приложения. В обработчиках событий ПередЗавершениемРаботыСистемы и ПриЗавершенииРаботыСистемы модуля управляемого приложения, а также в обработчиках ПередЗакрытием и ПриЗакрытии управляемых форм категорически запрещено открывать окна и выполнять любые серверные вызовы.

Это ограничение введено для оптимизации завершения сеансов и гарантированного закрытия веб-клиента. В момент закрытия вкладки браузера сетевое соединение разрывается, и платформа физически не может дождаться ответа от сервера или отобразить диалоговое окно пользователю.

Решение: механизм отложенного завершения работы

Чтобы выполнить серверный метод (например, запустить обмен РИБ), нам необходимо перехватить первую попытку закрытия системы, отменить ее через параметр Отказ = Истина, запустить клиентскую процедуру через обработчик ожидания, выполнить в ней обращение к серверу и затем программно закрыть базу.

Рассмотрим пошаговую реализацию этого механизма в модуле управляемого приложения.

  1. Объявим глобальную переменную для контроля состояния выполнения операции.
  2. В процедуре ПередЗавершениемРаботыСистемы проверим флаг. Если действие еще не выполнялось, установим отказ от закрытия и подключим однократный обработчик ожидания.
  3. В вызванной процедуре обработчика ожидания выполним необходимые серверные действия.
  4. Установим флаг в значение завершенности и вызовем закрытие сеанса.

Посмотрим на пример реализации в Модуле управляемого приложения:


Перем ДействияПередЗавершениемВыполнены;

Процедура ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения)
    
    // Если действия уже отработали, позволяем системе закрыться
    Если ДействияПередЗавершениемВыполнены = Истина Тогда
        Возврат;
    КонецЕсли;
    
    // Отменяем стандартное немедленное закрытие программы
    Отказ = Истина;
    
    // Подключаем однократный обработчик ожидания с минимальной задержкой
    ПодключитьОбработчикОжидания("ВыполнитьДействияПередВыходом", 0.1, Истина);
    
КонецПроцедуры

Процедура ВыполнитьДействияПередВыходом() Экспорт
    
    Попытка
        // Вызываем серверную логику (обмен данными, фиксация состояния)
        ВыполнитьСерверныеДействия();
    Исключение
        ЗаписьЖурналаРегистрации("ЗавершениеРаботы", УровеньЖурналаРегистрации.Ошибка,,, 
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
    
    // Устанавливаем флаг успешности, чтобы не уйти в бесконечный цикл отмены
    ДействияПередЗавершениемВыполнены = Истина;
    
    // Инициируем закрытие программы повторно
    ЗавершитьРаботуСистемы();
    
КонецПроцедуры

Проанализируем ключевые моменты этого кода:

  1. Параметр Истина в третьем аргументе метода ПодключитьОбработчикОжидания указывает на однократное выполнение процедуры.
  2. Обязательно оборачиваем серверный вызов в конструкцию Попытка ... Исключение. Если на сервере возникнет исключительная ситуация, пользователь не должен оказаться заблокированным в незакрывающейся программе.
  3. Переменная ДействияПередЗавершениемВыполнены предотвращает зацикливание при вызове метода ЗавершитьРаботуСистемы().

Разница между методами ЗавершитьРаботуСистемы и ПрекратитьРаботуСистемы

В зависимости от сценария можно использовать два метода завершения сеанса:

  1. ЗавершитьРаботуСистемы() — инициирует штатный процесс закрытия с повторным вызовом всех обработчиков закрытия открытых форм и приложения. Для этого метода обязательна проверка управляющего флага в ПередЗавершениемРаботыСистемы.
  2. ПрекратитьРаботуСистемы() — выполняет немедленный безусловный выход из программы без повторного вызова событий модуля приложения и форм. Если серверные процедуры уже выполнены и опрос обработчиков закрытия форм не требуется, вызов ПрекратитьРаботуСистемы() позволяет сразу выгрузить приложение.

Важные ограничения и риски

При использовании данного подхода необходимо учитывать несколько системных ограничений:

  1. Таймауты операционной системы: если пользователь закрывает не само окно 1С, а выполняет выключение или перезагрузку компьютера (shutdown), операционная система выделяет приложению ограниченный интервал времени на завершение процессов (обычно около 5 секунд). Если серверный обмен данными длится дольше, ОС принудительно завершит процесс клиентского приложения. Это чревато прерыванием транзакции или повреждением пакета обмена.
  2. Веб-клиент: при закрытии пользователем вкладки браузера сценарий с отменой закрытия и ожиданием асинхронного вызова блокируется большинством современных веб-браузеров в целях безопасности. Метод гарантированно работает в тонком и толстом клиентах.
  3. Длительные операции: если объем передаваемых данных в РИБ большой, интерфейс программы на время выполнения клиент-серверного вызова зависнет. Для длительных операций правильнее запускать фоновое задание на сервере или переносить выполнение обменов на серверное расписание с помощью регламентных заданий.
← На главную