Как избежать блокировки базы данных фоновыми заданиями при удалении объектов в 1С?

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

При выполнении массового удаления объектов в прикладных решениях 1С разработчики часто сталкиваются с ситуацией, когда процедура завершается ошибкой: «База данных заблокирована, сеанс такой-то, приложение Фоновое задание». Разберем механизм возникновения этой коллизии и детально проанализируем эффективные способы обхода ограничений монопольного режима.

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

Вызов стандартного платформенного метода УдалитьОбъекты(МассивСсылок, Истина, Найденные) жестко требует установки монопольного режима через УстановитьМонопольныйРежим(Истина), поскольку второй параметр Проверять = Истина запускает встроенный механизм контроля ссылочной целостности платформы. Однако на практике установка монопольного режима из пользовательского сеанса не гарантирует полной изоляции данных:

  1. Метод УстановитьМонопольныйРежим(Истина) запрещает интерактивный вход новых пользователей, но планировщик кластера серверов 1С продолжает запускать регламентные операции, порождая фоновые задания.
  2. В типовых конфигурациях (например, в «1С:Бухгалтерии предприятия») при старте клиентского приложения регистрируются многочисленные обработчики ожидания через ПодключитьОбработчикОжидания(), которые асинхронно порождают фоновые задачи.
  3. Если фоновое задание инициируется из сеанса, установившего монопольный режим, право на монопольный доступ перехватывается фоновым процессом.
  4. При длительной процедуре удаления СУБД эскалирует блокировки с отдельных записей до целых таблиц и базы в целом. Параллельно стартующее фоновое задание пытается прочитать данные или записать служебные параметры, что приводит к взаимоблокировке и аварийному прерыванию операции.

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

Способ 1. Запуск сеанса с ключом /DisableStartupJobs

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

Запустим сеанс «1С:Предприятия» через командную строку или добавим параметр в настройках запуска базы данных:

1cv8c.exe ENTERPRISE /IBName "МояБаза" /DisableStartupJobs

Параметр /DisableStartupJobs подавляет запуск стартовых регламентных процедур и фоновых задач, инициируемых типовыми подсистемами при входе пользователя. В результате клиентские таймеры не запускают конкурирующие серверные потоки, и монопольное удаление отрабатывает без конфликтов.

Способ 2. Отказ от монопольного режима: связка НайтиПоСсылкам и УдалитьОбъекты

Платформа 1С требует монопольный режим исключительно тогда, когда метод УдалитьОбъекты() выполняет проверку ссылок собственными силами. Если передать вторым параметром значение Ложь, требование к монопольному режиму снимается. Чтобы не нарушить ссылочную целостность базы данных, разделим задачу на два контролируемых этапа:

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

Посмотрим на пример реализации такого алгоритма:


// 1. Формируем массив объектов для проверки
МассивДляПоиска = Новый Массив;
Для Каждого Ссылка Из МассивСсылок Цикл
    МассивДляПоиска.Добавить(Ссылка);
КонецЦикла;

// 2. Ищем ссылки на удаляемые объекты
ТаблицаСсылок = НайтиПоСсылкам(МассивДляПоиска);

// 3. Отбираем только те объекты, на которые нет сторонних ссылок
МассивКБезусловномуУдалению = Новый Массив;
Для Каждого Ссылка Из МассивДляПоиска Цикл
    Отбор = Новый Структура("Ссылка", Ссылка);
    СтрокиСсылок = ТаблицаСсылок.НайтиСтроки(Отбор);
    
    // Если ссылок нет или все ссылки ведут только внутри удаляемого списка
    ЕстьВнешниеСсылки = Ложь;
    Для Каждого Стр Из СтрокиСсылок Цикл
        Если МассивДляПоиска.Найти(Стр.Данные) = Неопределено Тогда
            ЕстьВнешниеСсылки = Истина;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если Не ЕстьВнешниеСсылки Тогда
        МассивКБезусловномуУдалению.Добавить(Ссылка);
    КонецЕсли;
КонецЦикла;

// 4. Непосредственное удаление без требования монопольного режима
Если МассивКБезусловномуУдалению.Количество() > 0 Тогда
    УдалитьОбъекты(МассивКБезусловномуУдалению, Ложь);
КонецЕсли;

Этот подход устраняет необходимость в вызове УстановитьМонопольныйРежим(Истина), а значит, работа фоновых заданий не прервет процесс удаления.

Способ 3. Использование объектного метода Удалить() с порционной обработкой

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

Разберем по шагам, как организовать безопасное удаление порциями (транзакциями), чтобы избежать эскалации блокировок СУБД:


РазмерПорции = 200;
Счетчик = 0;

НачатьТранзакцию();
Попытка
    Для Каждого ТекСсылка Из МассивКБезусловномуУдалению Цикл
        Объект = ТекСсылка.ПолучитьОбъект();
        Если Объект <> Неопределено Тогда
            Объект.Удалить();
            Счетчик = Счетчик + 1;
        КонецЕсли;
        
        Если Счетчик % РазмерПорции = 0 Тогда
            ЗафиксироватьТранзакцию();
            НачатьТранзакцию();
        КонецЕсли;
    КонецЦикла;
    
    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ЗаписьЖурналаРегистрации("УдалениеДанных", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
    ВызватьИсключение;
КонецПопытки;

Разбиение массива на небольшие пакеты освобождает блокировки таблиц на уровне СУБД после каждой порции и предотвращает конфликт с параллельными фоновыми процессами.

Способ 4. Блокировка регламентных заданий на сервере

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

  1. В консоли администрирования кластера: открыть свойства нужной информационной базы и установить флаг «Блокировка регламентных заданий включена» (свойство ScheduledJobsDenied = True).
  2. Программная блокировка сеансов: создать объект БлокировкаСеансовИнформационнойБазы, вызвать УстановитьБлокировкуСеансов() с указанием параметра КодРазрешения, завершить текущие пользовательские сеансы и выполнить обработку удаления из служебного сеанса с ключом /UC.
  3. В клиентском интерфейсе: перед длительным монопольным циклом принудительно вызвать ОтключитьОбработчикОжидания() для известных таймеров конфигурации.

Таким образом, комбинация предварительного анализа связей через НайтиПоСсылкам() с последующим немонопольным порционным удалением является наиболее надежной стратегией при работе в клиент-серверных базах данных с высокой активностью фоновых задач.

← На главную