Как исправить ошибку "Серверные вызовы при завершении работы запрещены" в 1С?

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

При разработке управляемых форм в платформе 1С:Предприятие 8.3 разработчики часто сталкиваются с ошибкой "Серверные вызовы при завершении работы запрещены". Обычно это происходит, когда в обработчиках закрытия формы выполняется сохранение настроек, запись данных или обращение к серверным процедурам, а пользователь в этот момент закрывает само клиентское приложение 1С.

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

Почему возникает данная ошибка

Начиная с версии платформы 8.3.8 без режима совместимости, действует строгая модель завершения работы. Она разработана для унификации работы тонкого клиента и веб-клиента. В браузерах при закрытии вкладки или окна действуют ограничения, запрещающие выполнение синхронных сетевых запросов и показ блокирующих окон. Платформа 1С повторяет это поведение: в момент закрытия сеанса любые серверные вызовы блокируются на уровне ядра.

Запрет на серверные вызовы и интерактивные окна действует в следующих событиях:

  1. ПередЗавершениемРаботыСистемы и ПриЗавершенииРаботыСистемы в модуле управляемого приложения.
  2. ПередЗакрытием формы, если параметр ЗавершениеРаботы равен Истина.
  3. ПриЗакрытии формы, когда закрывается всё приложение.

Посмотрим на типичный ошибочный код, вызывающий исключение:


&НаКлиенте
Процедура ПриЗакрытии()
    // При выходе из 1С этот вызов приведет к ошибке
    СохранитьНастройкиНаСервере();
КонецПроцедуры

&НаСервере
Процедура СохранитьНастройкиНаСервере()
    ОбщегоНазначения.ХранилищеОбщихНастроекСохранить("МояОбработка", "Настройки", РеквизитФормы);
КонецПроцедуры

Рассмотрим рабочие варианты обхода и правильного проектирования логики сохранения настроек.

Способ 1. Сохранение данных в момент их изменения (рекомендованный стандарт 1С)

Стандарт разработки фирмы 1С предписывает отказаться от сохранения настроек в обработчике ПриЗакрытии. Вместо этого сохранение выполняется в момент непосредственного интерактивного действия пользователя. Чтобы не замедлять работу интерфейса и избежать лишней перерисовки формы, вызов сервера делают безконтекстным.

Проанализируем пример сохранения значения в событии изменения элемента формы или нажатия кнопки:


&НаКлиенте
Процедура НастройкаПриИзменении(Элемент)
    СохранитьНастройкуБезКонтекста(Объект.Настройка);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура СохранитьНастройкуБезКонтекста(ЗначениеНастройки)
    ОбщегоНазначения.ХранилищеОбщихНастроекСохранить("МояОбработка", "КлючНастройки", ЗначениеНастройки);
КонецПроцедуры

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

Способ 2. Использование встроенного механизма сохранения данных формы

Платформа 1С предоставляет декларативный механизм сохранения реквизитов формы в системном хранилище настроек без ручного вызова сервера в обработчиках закрытия.

Разберем по шагам, как его включить:

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

Способ 3. Разделение сценариев закрытия в событии ПередЗакрытием

Если сохранение обязательно должно происходить перед выходом из обработки, проанализируем параметр ЗавершениеРаботы в обработчике ПередЗакрытием. Если закрывается только сама форма, серверный вызов разрешен. Если же закрывается все приложение 1С, вызов сервера блокируется.

Посмотрим на реализацию раздельной логики:


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

Способ 4. Паттерн с отменой закрытия и обработчиком ожидания

Если в форме накоплен большой объем изменений (например, заполненная таблица тарифов), который критически важно сохранить на сервере даже при попытке закрытия всей программы, применим схему с отменой закрытия и асинхронным сохранением.

Обратите внимание: установка Отказ = Истина при ЗавершениеРаботы = Истина выводит диалог платформы с вопросом о завершении работы. Если пользователь нажимает «Продолжить работу», окно не закрывается, и управление возвращается клиенту. В этот момент мы можем запустить обработчик ожидания, сохранить данные и корректно закрыть форму.

Рассмотрим пример реализации:


&НаКлиенте
Переменная МодифицированностьНастроек;

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

&НаКлиенте
Процедура СохранитьНастройкиИАварийноЗакрыть()
    СохранитьНастройкиНаСервере();
    МодифицированностьНастроек = Ложь;
    Закрыть();
КонецПроцедуры

&НаСервере
Процедура СохранитьНастройкиНаСервере()
    // Выполняем сохранение в ХранилищеОбщихНастроек
    ОбщегоНазначения.ХранилищеОбщихНастроекСохранить("МояОбработка", "НастройкиТарифов", Объект.ТаблицаТарифов.Выгрузить());
КонецПроцедуры

Таким образом, для простых реквизитов рекомендуется использовать сохранение по событию ПриИзменении через &НаСервереБезКонтекста или штатное автосохранение настроек формы, а для сложных таблиц — проверку параметра ЗавершениеРаботы в событии ПередЗакрытием.

← На главную