Программное завершение сеанса 1С: рабочие способы и мифы
Содержание
Закрыть клиентское приложение из встроенного языка позволяет одна глобальная процедура — ЗавершитьРаботуСистемы(). Она завершает текущий сеанс 1С:Предприятие программно, при желании с перезапуском клиента. Всё остальное — закрытие форм, перехват исключений, снятие процесса — решает другие задачи, и путать их с выходом из программы не стоит.
Разберём, чем завершение сеанса отличается от закрытия формы и от исключения, как завершить работу тихо или с вопросом пользователю, как перехватить закрытие, что делать в веб-клиенте и как администратор снимает чужой зависший сеанс на сервере.
Глобальная процедура для выхода из программы
Корректный выход из клиента — это вызов:
// Завершить текущий сеанс без вопроса о сохранении
ЗавершитьРаботуСистемы(Ложь);
Процедура доступна только на стороне клиента — в модуле формы, в модуле команды, в клиентской процедуре общего модуля. Из серверного кода (регламентное задание, &НаСервере) закрыть клиентский сеанс нельзя: сервер не управляет окнами пользователя. Для завершения чужих сеансов используют административные инструменты — о них ниже.
В актуальных версиях платформы процедура принимает два необязательных параметра:
| Параметр | Что делает |
|---|---|
| Первый (С вопросом) | Истина — платформа покажет стандартное предупреждение о несохранённых данных; Ложь — завершит сразу |
| Второй (Перезапустить) | Истина — после выхода клиент запустится заново |
Тихое завершение без диалогов:
ЗавершитьРаботуСистемы(Ложь, Ложь);
Два типовых сценария, ради которых код закрывает сеанс:
- После смены региональных или пользовательских настроек, которые платформа читает только при старте. Перезапуск применяет их без ручного переоткрытия:
СохранитьНастройкиПользователя();
ЗавершитьРаботуСистемы(Ложь, Истина); // выход с перезапуском
- Принудительный выход перед обновлением. Здесь важно не «убить» сеанс, а дать клиенту закрыться штатно, предупредив человека и оставив шанс сохранить данные:
Сообщить("База закрывается на обновление. Сохраните данные.");
ЗавершитьРаботуСистемы(Истина); // с вопросом о сохранении
Насчёт сохранности данных: всё, что было записано и зафиксировано до выхода, в базе остаётся. А вот незавершённая транзакция (между НачатьТранзакцию() и ЗафиксироватьТранзакцию()) при закрытии сеанса откатывается платформой целиком — наполовину записанных данных не бывает. Поэтому длинные операции с записью лучше доводить до конца, а не прерывать выходом из программы.
Ставьте вызов ЗавершитьРаботуСистемы() последней строкой процедуры. Платформа завершает текущий клиентский вызов, и код после этой строки всё ещё может отработать — не рассчитывайте, что выполнение прервётся мгновенно.
В старых конфигурациях на обычном приложении (толстый клиент без управляемых форм) за выход отвечала процедура ПрекратитьРаботуСистемы() без параметров. В управляемом приложении 8.3 она не применяется — используйте ЗавершитьРаботуСистемы().
Перехват и отмена закрытия сеанса
Выход из программы можно не только инициировать, но и перехватить. За это отвечают два события в модуле управляемого приложения (МодульУправляемогоПриложения), которые срабатывают независимо от того, кто инициировал выход — пользователь кнопкой или ваш код.
Перед завершением вызывается обработчик, в котором ещё можно отменить выход:
Процедура ПередЗавершениемРаботыСистемы(Отказ, ТекстПредупреждения)
Если ЕстьНезавершённыеОперации() Тогда
Отказ = Истина; // выход не состоится
ТекстПредупреждения = "Завершите текущую операцию перед выходом";
КонецЕсли;
КонецПроцедуры
Установка Отказ = Истина блокирует закрытие — удобно, когда нельзя дать пользователю выйти с незаписанными документами или незавершённой обработкой.
При завершении вызывается обработчик для финального кода — здесь отменить выход уже нельзя, зато можно выполнить уборку: сбросить временные данные, записать в журнал регистрации, закрыть внешнее соединение:
Процедура ПриЗавершенииРаботыСистемы()
ОчиститьВременныеФайлыСеанса();
ЗаписьЖурналаРегистрации("Сеанс.Завершение",
УровеньЖурналаРегистрации.Информация, , ,
"Пользователь завершил работу");
КонецПроцедуры
Запись в журнал регистрации при выходе помогает потом разобраться, кто и когда закрыл базу, — особенно если выход инициирует код, а не человек.
Не затягивайте код в этих обработчиках. Долгие операции при закрытии раздражают пользователя и могут выглядеть как зависание. Тяжёлую фоновую работу выносите в регламентные задания на сервере, а не в момент выхода из клиента.
Оба обработчика живут в модуле управляемого приложения. Открыть его можно из конфигуратора: в дереве конфигурации вызовите контекстное меню на корневом узле и выберите открытие модуля приложения. Если обработчиков там ещё нет, их добавляют вручную по именам событий.
Эти два события — штатный механизм контроля выхода. Если задача звучит как «не дать закрыть программу, пока…» — решается она именно здесь, а не исключениями.
Почему через исключение сеанс не закрывается
Частое заблуждение: «выбросим исключение — и программа закроется». Это не так. Исключение не завершает работу 1С, оно лишь прерывает текущую операцию.
Конструкция Попытка … Исключение … КонецПопытки ловит ошибку, а оператор ВызватьИсключение её порождает. Управление при этом поднимается по стеку вызовов до ближайшего обработчика или до платформы, которая покажет пользователю сообщение об ошибке. Сам сеанс остаётся открытым.
Попытка
ПровестиДокумент();
Исключение
Сообщить("Не удалось провести: " + ОписаниеОшибки());
КонецПопытки;
Если задача была не «закрыть программу», а отменить действие (запись, проведение, открытие формы), то нужен не выход из системы, а отказ от операции. В обработчиках событий для этого есть параметр Отказ:
&НаСервере
Процедура ПередЗаписьюНаСервере(Отказ, ТекущийОбъект)
Если ТекущийОбъект.Сумма = 0 Тогда
Отказ = Истина; // запись не состоится
КонецЕсли;
КонецПроцедуры
Выброс исключения в таком обработчике тоже отменит запись, но вдобавок покажет пользователю красное окно ошибки. Для штатной отмены чаще корректнее установить Отказ = Истина и при необходимости вывести понятное сообщение через Сообщить().
Вывод простой: исключение — инструмент обработки ошибок, а не способ выйти из приложения. Для выхода есть ЗавершитьРаботуСистемы().
Закрытие форм и окон перед выходом
Отдельной глобальной команды вроде «очистить все формы» в платформе нет. Закрытие окна и завершение сеанса — разные операции.
Закрыть текущую управляемую форму:
ЭтаФорма.Закрыть();
Вернуть значение в вызвавшую форму и закрыться (типично для форм выбора):
ОповеститьОВыбореИЗакрыть(ВыбранныйЭлемент);
Когда вы вызываете ЗавершитьРаботуСистемы(), платформа сама пытается закрыть все открытые формы. Если в каком-то окне есть несохранённые данные, а первый параметр процедуры равен Истина, пользователь получит стандартный вопрос о сохранении. При Ложь система закроет окна без вопросов — несохранённое при этом потеряется.
Тихое завершение (ЗавершитьРаботуСистемы(Ложь)) не спрашивает про несохранённые данные. Применяйте его, только когда уверены, что ничего важного в открытых формах не осталось, или сначала сами сохраните нужные объекты в коде.
Если задача — закрыть одно окно и оставить программу работать, вызывайте Закрыть() у нужной формы, а не завершение всей системы.
Особенности веб-клиента и тонкого клиента
Процедура ЗавершитьРаботуСистемы() работает во всех клиентах — толстом, тонком и веб. Но поведение различается:
- Тонкий клиент (
1cv8c) и толстый клиент (1cv8) закрывают приложение полностью. СПерезапустить = Истиназапускается новый экземпляр. - Веб-клиент работает внутри вкладки браузера. Платформа завершает сеанс 1С, но закрыть саму вкладку браузер по соображениям безопасности может запретить — это ограничение браузера, а не 1С. С перезапуском веб-клиент перезагружает страницу приложения.
Не рассчитывайте, что в веб-клиенте код гарантированно закроет вкладку. Логика приложения не должна зависеть от того, исчезло окно браузера или нет — ориентируйтесь на завершение самого сеанса.
Остальная логика (параметры процедуры, события завершения, отмена через Отказ, закрытие форм через Закрыть()) в веб-клиенте идентична обычному клиенту.
Аварийное завершение процесса в операционной системе
Когда клиент завис и не реагирует, встроенный язык уже не поможет — код в зависшем сеансе не выполняется. Остаётся снять процесс средствами ОС.
На Windows клиент — это процесс 1cv8 (толстый) или 1cv8c (тонкий):
taskkill /F /IM 1cv8.exe
Если открыто несколько клиентов, а завис только один, снимайте по идентификатору процесса (PID), а не все сразу по имени — PID виден в Диспетчере задач на вкладке с подробностями. На Linux клиент тоже называется 1cv8, зависший процесс снимают командой kill по его PID (его показывает ps или системный монитор). Принудительное снятие на обеих системах — одинаково грубая операция с одним и тем же риском потери данных.
Снятие процесса — аварийный метод. Несохранённые данные в открытых формах пропадут. Для файловой базы незакрытый сеанс может оставить блокировку (файл 1Cv8.1CL) — после снятия процесса убедитесь, что в базу больше никто не вошёл, прежде чем запускать её снова. Делайте это только с конкретным зависшим клиентом, а не со всеми процессами подряд.
Снимать серверные процессы (rphost, ragent) на боевом сервере без необходимости нельзя: оборвутся все сеансы пользователей этого кластера. Это задача администратора в согласованное окно, а не способ «закрыть 1С».
Как администратор завершает чужой сеанс
Если нужно выкинуть из базы конкретного пользователя (например, тот забыл выйти перед обновлением), сеанс завершают на стороне сервера:
- Консоль администрирования серверов 1С — в ветке кластера откройте список сеансов, найдите нужный по имени пользователя и удалите его.
- Утилита
racиз командной строки сервера:
rac session list --cluster=<идентификатор кластера>
rac session terminate --cluster=<идентификатор кластера> --session=<идентификатор сеанса>
Идентификаторы берутся из вывода rac session list. Полный перечень параметров смотрите в rac help — не подставляйте ключи наугад.
Если нужно выгнать сразу всех перед обновлением, аккуратнее не завершать сеансы по одному, а включить в консоли кластера блокировку начала сеансов: новые пользователи не войдут, а текущих можно корректно попросить выйти. Это мягче принудительного завершения.
Завершение чужого сеанса обрывает его работу так же, как снятие процесса: несохранённые данные пользователя теряются. Предупредите человека, если это не аварийная ситуация.
Сравнение способов завершения
ЗавершитьРаботуСистемы(Ложь) на клиенте. Нужен перезапуск — вторым параметром Истина.ЭтаФорма.Закрыть() у нужной формы.Отказ = Истина.ПередЗавершениемРаботыСистемы и поставьте Отказ = Истина.rac session terminate.1cv8 средствами ОС. Будьте готовы к потере несохранённых данных.| Способ | Что закрывает | Когда применять | Риск |
|---|---|---|---|
ЗавершитьРаботуСистемы(Ложь) | Свой сеанс, тихо | Штатный выход из кода | Теряются несохранённые данные открытых форм |
ЗавершитьРаботуСистемы(Истина) | Свой сеанс, с вопросом | Выход с шансом сохранить | Пользователь может отменить |
ПередЗавершениемРаботыСистемы | Отменяет выход | Запретить закрытие по условию | Низкий |
Закрыть() у формы | Одно окно | Закрыть форму, не выходя | Низкий |
Отказ = Истина | Ничего не закрывает | Отменить запись/проведение | Низкий |
Консоль кластера / rac | Чужой сеанс | Выгнать пользователя с сервера | Потеря его данных |
taskkill по 1cv8 | Процесс клиента | Зависший клиент | Высокий: потеря данных, блокировки |
Правило выбора короткое: для планового выхода из кода — только ЗавершитьРаботуСистемы(). Процесс и чужие сеансы снимают лишь в аварийных ситуациях и с пониманием последствий.
Частые вопросы
Можно ли закрыть 1С из серверного кода или регламентного задания?
ЗавершитьРаботуСистемы() — клиентская процедура, она управляет окном пользователя. На сервере клиентских сеансов нет. Чтобы завершить чужой сеанс с сервера, используйте консоль кластера или rac session terminate.Как закрыть программу без вопроса о сохранении данных?
Ложь: ЗавершитьРаботуСистемы(Ложь). Платформа закроет формы без диалога. Несохранённое при этом потеряется — сохраните нужное заранее.Почему после `ЗавершитьРаботуСистемы()` следующая строка кода всё равно выполняется?
Можно ли запретить пользователю закрывать программу?
ПередЗавершениемРаботыСистемы в модуле управляемого приложения: установите в нём Отказ = Истина. Пользователь увидит ваш текст предупреждения и останется в системе.Как перезапустить клиент из кода?
Истина: ЗавершитьРаботуСистемы(Ложь, Истина). Толстый и тонкий клиент запустятся заново, веб-клиент перезагрузит страницу.