Почему фоновое задание, запущенное при отмене проведения документа, не видит актуальных данных?

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

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

Причина проблемы: Изоляция транзакций

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

Последовательность событий выглядит так:

  1. Вызывается обработчик ПриЗаписи(). В этот момент флаг Проведен у документа уже установлен в Ложь.
  2. Следом вызывается обработчик ОбработкаУдаленияПроведения(). Внутри него старые движения документа еще доступны, но уже помечены на удаление.
  3. Платформа выполняет удаление записей из регистров.
  4. Только после успешного завершения всех шагов транзакция фиксируется (выполняется Commit).

Теперь рассмотрим, что происходит с фоновым заданием:

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

Важный момент: запуск фонового задания из транзакции — это логически небезопасно. Представим ситуацию: вы запустили фоновое задание, а после этого в основной транзакции произошла ошибка, и она была отменена (Rollback). Документ остался проведенным, но фоновое задание уже выполняется, оперируя неверными предположениями, что может привести к нарушению целостности данных.

Решение 1: Использовать отложенные механизмы

Самый надежный и правильный способ — выполнять нужные действия после того, как основная транзакция будет гарантированно и успешно завершена. Для этого существуют специальные механизмы.

Способ А: Отложенные обработчики из Библиотеки стандартных подсистем (БСП)

Если ваша конфигурация использует БСП, это предпочтительный вариант. Механизм отложенных обработчиков позволяет зарегистрировать вызов процедуры, которая будет выполнена платформой автоматически после успешной фиксации основной транзакции.

В обработчике ОбработкаУдаленияПроведения вы регистрируете вызов нужного метода, а БСП берет на себя заботу о его своевременном и безопасном запуске. Это гарантирует, что ваш код будет работать с уже актуальными, записанными в базу данных, сведениями.

Способ Б: Собственная очередь заданий

Если БСП не используется, можно реализовать похожий механизм самостоятельно. Этот подход очень надежен, так как устойчив даже к перезагрузке сервера.

  1. Создайте регистр сведений (например, ОчередьЗаданийНаАктуализацию) с измерениями для хранения информации о задаче (например, СсылкаНаДокумент, ТипЗадачи).
  2. В обработчике ОбработкаУдаленияПроведения добавляйте в этот регистр новую запись о том, что для данного документа требуется выполнить актуализацию.
  3. Создайте регламентное задание, которое запускается с небольшим интервалом (например, раз в минуту).
  4. Это задание считывает записи из регистра-очереди, выполняет необходимую логику, а после успешной обработки удаляет запись из очереди.

Решение 2: Передача данных в фоновое задание по значению

Этот подход можно использовать, если объем данных невелик и риск, связанный с возможной отменой основной транзакции, приемлем.

Суть в том, чтобы не передавать в фоновое задание ссылку на объект, а вместо этого передать все необходимые для работы данные напрямую.

  1. В обработчике ОбработкаУдаленияПроведения соберите все нужные данные в структуру или соответствие. Например:
    
    ДанныеДляАктуализации = Новый Структура;
    ДанныеДляАктуализации.Вставить("Номенклатура", ДокументОбъект.Товар);
    ДанныеДляАктуализации.Вставить("Склад", ДокументОбъект.Склад);
    ДанныеДляАктуализации.Вставить("СтарыйСтатус", "Проведен");
    
  2. Сериализуйте эту структуру (например, в строку JSON) или передайте как есть в параметры фонового задания.
  3. Фоновое задание получает эти данные и работает с ними, не обращаясь к базе данных за состоянием отмененного документа.

Помните о недостатке: этот метод не решает проблему возможной отмены основной транзакции. Фоновое задание все равно будет запущено.

Выводы и рекомендации

Прямой вызов фонового задания из транзакционных обработчиков событий документа (ПриЗаписи, ОбработкаПроведения, ОбработкаУдаленияПроведения) для работы с данными этой же транзакции — это некорректный подход из-за изоляции транзакций.

Рассмотрим и будем использовать более надежные архитектурные решения:

Такой подход обеспечит целостность данных и предсказуемое поведение вашей системы.

← На главную