В практике разработки на платформе 1С часто возникает задача: после успешного проведения основного документа необходимо автоматически сформировать и провести связанный с ним документ (например, на основании). Сложность заключается в том, что если второй документ не сможет провестись по какой-либо причине (нехватка остатков, не заполнены обязательные реквизиты), стандартные механизмы платформы откатят транзакцию и первого документа тоже. Это происходит из-за того, что в 1С нет полноценных вложенных транзакций, которые могли бы завершаться независимо от родительской.
В этой статье мы подробно разберем, почему простая конструкция Попытка...Исключение внутри процедуры ОбработкаПроведения не всегда спасает ситуацию, и рассмотрим надежные архитектурные решения этой задачи.
Многие начинающие разработчики пытаются решить задачу «в лоб», вызывая проведение второго документа внутри транзакции первого в блоке Попытка. Однако стоит помнить: если ошибка при проведении второго документа произошла на уровне базы данных (например, нарушение уникальности или конфликт блокировок), вся транзакция помечается как «битая». Даже если вы перехватили ошибку в 1С-коде, при попытке завершить процедуру ОбработкаПроведения платформа выдаст фатальную ошибку: «Транзакция уже испорчена и не может быть зафиксирована».
Поэтому для надежной работы нам нужно разнести процессы проведения двух документов во времени или в разные программные контексты.
Это классический и самый надежный способ, подходящий для систем с высокой нагрузкой. Суть метода заключается в разделении логики формирования данных и логики их проведения.
Алгоритм реализации:
РегистрСведений (например, «ОчередьПроведенияДокументов»), где основным измерением будет Ссылка на первый документ.ОбработкаПроведения первого документа будем записывать в этот регистр признак того, что для данного объекта нужно сформировать второй документ.Рассмотрим пример кода для записи в очередь:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Основная логика проведения первого документа
...
// Регистрируем необходимость создания второго документа
МенеджерЗаписи = РегистрыСведений.ОчередьПроведенияДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Объект = ЭтотОбъект.Ссылка;
МенеджерЗаписи.ДатаРегистрации = ТекущаяДата();
МенеджерЗаписи.Состояние = Перечисления.СостоянияЗадач.ВТработе;
МенеджерЗаписи.Записать();
КонецПроцедуры
Этот подход гарантирует, что основной документ всегда будет проведен, а зависимый «подтянется» следом, как только это станет возможным.
Разберем ситуацию, когда проведение второго документа должно произойти максимально быстро после первого. В платформе 1С есть интересная особенность работы метода ФоновыеЗадания.Выполнить(). Если вызвать его внутри транзакции, само фоновое задание фактически стартует только после успешной фиксации (COMMIT) основной транзакции.
Преимущества этого метода:
Пример инициализации фонового задания:
ПараметрыПроцедуры = Новый Массив;
ПараметрыПроцедуры.Добавить(ЭтотОбъект.Ссылка);
ФоновыеЗадания.Выполнить("МойОбщийМодуль.СформироватьСвязанныйДокумент",
ПараметрыПроцедуры,
Новый УникальныйИдентификатор(),
"Проведение зависимого документа");
Внутри процедуры СформироватьСвязанныйДокумент в общем модуле необходимо обязательно использовать блок Попытка...Исключение, чтобы ошибка проведения не «уронила» само фоновое задание и позволила корректно зафиксировать результат (например, просто записать документ без проведения).
Если ваша конфигурация построена на БСП, проанализируем возможности подсистемы «Очередь заданий» или механизмы отложенного проведения. В БСП существует удобный паттерн — ДополнительныеРезультатыПроведения.
В момент проведения документа вы можете поместить в специальную структуру в параметрах проведения инструкции. После завершения транзакции на стороне клиента (если документ проводился из формы), система может обработать эти инструкции и запустить процесс создания второго документа. Это позволяет сохранить интерактивную связь: пользователь сразу увидит результат работы по второму документу.
Проанализируем ситуацию: часто второй документ не проводится из-за банальных ошибок (недостаток товара, пустые счета учета). Чтобы минимизировать такие случаи, мы можем выполнить «холостой прогон» перед тем, как вообще начинать проведение первого документа.
Выясним причину возможного отказа заранее:
ПроверитьВозможностьПроведенияСвязанногоДокумента().ОбработкаПроведения первого документа или даже в обработчике ПередЗаписью.Важно помнить, что проведение второго документа «встык» к первому (особенно в одной транзакции) резко увеличивает время удержания блокировок. Если оба документа делают движения по одним и тем же регистрам накопления (например, «Запасы»), это может привести к Deadlocks (взаимным блокировкам) при одновременной работе нескольких пользователей.
Вывод: Вынос формирования зависимых документов в фоновые процессы или регламентные задания — это не только способ обойти ограничения транзакций, но и стандарт проектирования высокопроизводительных (Highload) систем на базе 1С.
Рассмотренные нами методы позволяют сделать систему отказоустойчивой. Мы рекомендуем использовать Решение 1 (Регистр очереди) для гарантированного выполнения задач в фоновом режиме и Решение 2 (Фоновые задания) для оперативного реагирования системы.