Зависший запрос в 1С 8.3: как его остановить, не роняя сервер
Содержание
Чтобы отменить запрос в 1С 8, который уже выполняется на сервере, откройте консоль администрирования кластера, найдите сеанс пользователя в списке Сеансы и выберите для него прерывание текущего серверного вызова. Сеанс останется жив, а запрос остановится с ошибкой. Если такой команды нет или она не помогла, завершают весь сеанс, а в крайнем случае снимают соединение на стороне СУБД.
Порядок методов простой: от мягкого к жёсткому. Сначала то, что откатывает только сам запрос, потом то, что обрывает работу пользователя, и уже в конце — вмешательство в базу данных. Ниже каждый способ разобран с командами, кодом и рисками.
Что можно остановить из самой программы
В клиентском приложении у пользователя есть один штатный инструмент — сочетание Ctrl+Break. Оно прерывает выполнение кода встроенного языка, который работает на клиенте: долгий цикл в обработке, перебор строк табличной части на форме.
С запросом сложнее. В клиент-серверной базе запрос всегда выполняется на сервере 1С, а оттуда — в СУБД. Клиент в это время просто ждёт ответа. Поэтому:
- ⌨️
Ctrl+Breakнадёжно останавливает клиентский код и циклы, где разработчик вызвалОбработкаПрерыванияПользователя(); - 🖥️ долгий серверный вызов с запросом так обычно не остановить — нужен администратор и консоль кластера;
- ❌ закрытие окна 1С через диспетчер задач запрос не отменяет: клиент исчезает, а сеанс на сервере какое-то время продолжает работу, пока сервер не обнаружит разрыв соединения.
Снимать процесс 1cv8c.exe или 1cv8.exe в диспетчере задач — худший вариант. Запрос на сервере продолжит выполняться, блокировки останутся, а пользователь при повторном входе может упереться в свой же «висящий» сеанс.
Как встроить прерывание в свою обработку
Если вы пишете обработку с долгим циклом на клиенте или в файловой базе, вызывайте ОбработкаПрерыванияПользователя() внутри цикла. Процедура проверяет, нажал ли пользователь Ctrl+Break, и если да — предлагает прервать выполнение.
Для Каждого Строка Из ТаблицаДанных Цикл
ОбработкаПрерыванияПользователя();
// обработка строки
ОбработатьСтроку(Строка);
КонецЦикла;
Для одного большого запроса это не работает
: пока Запрос.Выполнить() не вернул результат, до проверки в цикле дело не доходит. Для таких случаев есть фоновые задания — о них ниже.
Прерывание через консоль кластера серверов
Главный инструмент администратора — оснастка «Администрирование серверов 1С:Предприятия» (консоль кластера). Она подключается к агенту сервера по порту 1540 и показывает всё, что происходит в кластере.
Как найти сеанс, который держит запрос
- Откройте консоль, разверните
Кластеры → <ваш кластер> → Информационные базы → <база> → Сеансы. - Добавьте в список колонки с длительностью текущего вызова и временем, захваченным СУБД (настраиваются через выбор колонок списка).
- Отсортируйте по длительности вызова. Сеанс с вызовом в десятки минут и растущим временем СУБД — ваш кандидат.
- Сверьте пользователя и компьютер, прежде чем что-то обрывать. Часто «висит» не сотрудник, а регламентное или фоновое задание.
💡 Список сеансов можно открыть и на уровне всего кластера, а не одной базы. Так быстрее найти виновника, если тормозят сразу несколько баз на одном сервере.
Три уровня вмешательства
| Действие в консоли | Что происходит | Последствия для пользователя |
|---|---|---|
| Прервать текущий серверный вызов | Платформа останавливает выполняемый вызов, транзакция откатывается | Пользователь получает ошибку, но остаётся в программе |
| Удалить (завершить) сеанс | Сеанс закрывается целиком | Несохранённые данные теряются, нужно входить заново |
Завершить рабочий процесс rphost | Обрываются все сеансы этого процесса | Падает работа у всех, кто был на этом процессе |
Команда прерывания серверного вызова появилась в платформе 8.3 не с первых версий. Если в контекстном меню сеанса её нет — обновите платформу или переходите ко второму уровню.
Завершение рабочего процесса обрывает сеансы всех пользователей на нём. Делайте это только когда другие способы не сработали, и предупредите людей заранее — в обеденный перерыв или после рабочего дня, если запрос не критичен.
То же самое из командной строки через rac
Если графической консоли нет под рукой (например, сервер на Linux), используют утилиту rac. Для неё должен быть запущен сервис администрирования ras.
rem 1. Узнать идентификатор кластера
rac cluster list
rem 2. Получить список сеансов кластера
rac session list --cluster=<uuid-кластера>
rem 3. Завершить сеанс
rac session terminate --cluster=<uuid-кластера> --session=<uuid-сеанса>
Если на кластере задан администратор, добавьте параметры --cluster-user и --cluster-pwd. Для прерывания только текущего вызова в актуальных версиях есть отдельная подкоманда группы session — её точное имя и параметры для вашей версии смотрите в rac help session.
💡 Вывод rac session list длинный. Сохраните его в файл и ищите нужного пользователя по полю user-name — так меньше шансов ошибиться UUID.
Как отменить запрос программно, из кода
Сам себя запрос не отменит. Код, который вызвал Запрос.Выполнить(), ждёт результата и ничего другого сделать не может. Поэтому долгий запрос, который пользователь должен уметь остановить, выносят в фоновое задание.
Схема с фоновым заданием
- Форма запускает серверную процедуру в фоне через
ФоновыеЗадания.Выполнить()и запоминает уникальный идентификатор задания. - Форма периодически проверяет состояние задания через обработчик ожидания.
- По кнопке «Отменить» сервер находит задание и вызывает у него
Отменить().
&НаСервере
Функция ЗапуститьОтчетВФоне()
Параметры = Новый Массив;
Параметры.Добавить(Объект.НачалоПериода);
Параметры.Добавить(Объект.КонецПериода);
Задание = ФоновыеЗадания.Выполнить(
"МойОбщийМодуль.СформироватьДанные", Параметры, , "Долгий отчёт");
Возврат Задание.УникальныйИдентификатор;
КонецФункции
&НаСервереБезКонтекста
Процедура ОтменитьЗадание(ИдентификаторЗадания)
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
Если Задание <> Неопределено
И Задание.Состояние = СостояниеФоновогоЗадания.Активно Тогда
Задание.Отменить();
КонецЕсли;
КонецПроцедуры
Процедура МойОбщийМодуль.СформироватьДанные должна лежать в серверном общем модуле и принимать два параметра — начало и конец периода. После отмены задание переходит в состояние «Отменено», транзакция внутри него откатывается.
Отмена фонового задания — команда платформе, а не мгновенный обрыв. Если в этот момент СУБД выполняет тяжёлый запрос, остановка может занять время, пока СУБД обработает отмену и откатит изменения.
В типовых конфигурациях на библиотеке стандартных подсистем такая схема уже реализована для отчётов: у долгого отчёта на форме появляется индикатор и кнопка отмены формирования. Если вы дорабатываете типовую, используйте механизм длительных операций БСП, а не пишите свой с нуля.
Почему нет «таймаута запроса»
У объекта Запрос нет свойства, которое ограничило бы время выполнения. Ограничить можно иначе:
- ⏱️ запустить запрос в фоне и отменять задание, если оно работает дольше заданного порога;
- 🛡️ настроить ограничения потребления ресурсов в кластере (об этом в разделе про профилактику);
- 🗄️ задать ограничения на стороне СУБД, но это уже решение администратора базы данных.
Снятие запроса на уровне СУБД
Когда консоль 1С не помогает — вызов не прерывается, сеанс не удаляется, — остаётся СУБД. Это последний рубеж, и ошибиться здесь проще всего.
Microsoft SQL Server
Найти долгие запросы и цепочки блокировок можно через динамическое представление запросов:
SELECT r.session_id,
r.blocking_session_id,
r.status,
r.wait_type,
r.total_elapsed_time / 1000 AS seconds,
s.host_name,
s.program_name
FROM sys.dm_exec_requests r
JOIN sys.dm_exec_sessions s ON s.session_id = r.session_id
WHERE s.is_user_process = 1
ORDER BY r.total_elapsed_time DESC;
Колонка blocking_session_id показывает, кто кого держит. Вершина цепочки — сессия, которая блокирует других, но сама никем не заблокирована. Её и снимают:
KILL 57; -- номер session_id из запроса выше
PostgreSQL
SELECT pid, state, now() - query_start AS duration,
pg_blocking_pids(pid) AS blocked_by, left(query, 100)
FROM pg_stat_activity
WHERE state <> 'idle'
ORDER BY duration DESC;
Сначала пробуйте мягкую отмену — она останавливает только текущий запрос:
SELECT pg_cancel_backend(12345);
Если не сработало — обрыв соединения целиком:
SELECT pg_terminate_backend(12345);
Что важно знать перед KILL
- 🔁 СУБД откатывает транзакцию. Если запрос писал много данных, откат может идти дольше, чем сам запрос работал до отмены.
- 👤 Сервер 1С держит соединения с СУБД от имени рабочих процессов, поэтому в
host_nameвы увидите сервер 1С, а не компьютер бухгалтера. Связывайте сессию СУБД с пользователем по времени начала и тексту запроса, а не по имени компьютера. - 🚫 Не снимайте системные процессы СУБД и сессии, которые никем не заблокированы и ничего не держат.
Обрыв соединения в СУБД — для пользователя 1С это авария. Его сеанс получит ошибку обращения к базе. Делайте это, только если вы точно определили виновника и иначе остановить его нельзя.
Профилактика: таймауты и ограничения в кластере
Лучше, чтобы запрос не успевал парализовать базу, чем каждый раз снимать его вручную. Платформа даёт для этого несколько настроек.
Ограничения в свойствах кластера
В свойствах кластера (контекстное меню кластера в консоли → свойства) задаются лимиты памяти рабочих процессов. Ключевой для нашей темы — безопасный расход памяти за один вызов. Если серверный вызов превышает этот объём, платформа прерывает его с ошибкой. Это защищает сервер от запроса, который выбирает в память миллионы строк.
Ограничения потребления ресурсов
В актуальных версиях 8.3 в консоли кластера есть раздел счётчиков и ограничений потребления ресурсов. Логика такая:
- Создаёте счётчик — например, по длительности вызова или по времени работы СУБД, с отбором по базе или пользователю.
- Создаёте ограничение на этот счётчик с порогом.
- Выбираете действие при превышении: записать в журнал, прервать текущий серверный вызов или завершить сеанс.
Начинайте с действия «только записать» на неделю. Так вы увидите, какие операции превышают порог законно — закрытие месяца , расчёт себестоимости, — и не оборвёте их в боевой день.
Таймаут управляемых блокировок
Когда запрос висит не потому, что тяжёлый, а потому что ждёт блокировку, платформа сама прервёт ожидание. Типичный текст ошибки: Превышено максимальное время ожидания предоставления блокировки. Это нормальная защита: лучше пользователь получит ошибку через 20 секунд, чем будет ждать бесконечно.
Почему запрос зависает: диагностика и оптимизация
Отмена снимает симптом. Чтобы запрос не повис завтра, нужно найти причину. Их обычно три группы: сам запрос написан неэффективно, он ждёт чужую блокировку, или СУБД построила плохой план.
Где искать виновника
| Инструмент | Что показывает | Когда использовать |
|---|---|---|
| Замер производительности в конфигураторе | Какие строки кода занимают больше всего времени | Тормозит конкретная обработка или отчёт |
Технологический журнал (logcfg.xml) | Длительность запросов к СУБД, ожидания блокировок, взаимоблокировки | Проблема плавающая, на рабочем сервере |
| Журнал регистрации | Кто и когда запускал операции, ошибки | Нужно восстановить последовательность событий |
| План запроса в СУБД | Как СУБД выполняет запрос: сканы таблиц, индексы | Запрос найден, нужно понять, почему он медленный |
Для технологического журнала полезны события по запросам к СУБД (DBMSSQL для SQL Server, DBPOSTGRS для PostgreSQL) с отбором по длительности, а также события ожидания и таймаута блокировок (TLOCK, TTIMEOUT, TDEADLOCK). Включайте журнал с фильтром по длительности: без фильтра он за час заполнит диск.
Типовые ошибки в тексте запроса
- 🐢 Соединение с подзапросом вместо временной таблицы. Перенесите выборку во временную таблицу и добавьте
ИНДЕКСИРОВАТЬ ПОдля поля соединения. - 🐢 Условие на виртуальную таблицу регистра в
ГДЕ, а не в её параметрах. Отбор в параметрахОстатки(&Дата, Склад = &Склад)срабатывает до расчёта, вГДЕ— после. - 🐢 Обращение через точку к полю составного типа. Платформа соединяет все таблицы возможных типов. Используйте
ВЫРАЗИТЬ(Поле КАК Документ.РеализацияТоваровУслуг). - 🐢
ИЛИв условии соединения. Часто мешает СУБД использовать индекс; помогает разбиение на части черезОБЪЕДИНИТЬ ВСЕ. - 🐢 Запрос в цикле. Тысяча маленьких запросов тормозит не меньше одного огромного — соберите данные одним запросом.
Блокировки и долгие транзакции
Если по технологическому журналу видно, что запрос в основном ждёт, а не работает, ищите того, кто держит блокировку. Чаще всего это длинная транзакция: проведение большого документа, групповое перепроведение, обмен данными с записью тысяч объектов в одной транзакции. Лечится дроблением на порции и переносом массовых операций на нерабочее время.
Частые вопросы
Откатятся ли изменения, если прервать запрос в середине?
Почему после завершения сеанса пользователь всё равно «висит» в списке?
Можно ли отменить запрос в файловой базе?
Ctrl+Break в клиенте и завершение процесса клиента, который выполняет запрос. Сервер СУБД тут не участвует, данные лежат в файле 1Cv8.1CD.Пользователь сам может прервать долгий отчёт?
Нужны ли права администратора кластера, чтобы прерывать сеансы?
rac потребуют их логин и пароль. Без них сеанс завершить нельзя.