Реализация фоновых процессов в 1С:Предприятие — это эффективный способ вынести тяжелые или периодические задачи из основного потока интерфейса, чтобы пользователь не сталкивался с зависаниями программы. Однако при разработке таких механизмов начинающие специалисты часто допускают ошибки, связанные с изоляцией сеансов и управлением временем жизни временного хранилища. В данной статье мы подробно разберем, как правильно организовать мониторинг документов, почему возникает ошибка доступа к временному хранилищу и как сделать архитектуру решения профессиональной.
Проанализируем ситуацию, описанную автором: программа выдает ошибку «Неправильный путь к файлу» при вызове метода ПолучитьИзВременногоХранилища. Выясним причину этого поведения. Временное хранилище в 1С напрямую привязано к сеансу пользователя. Фоновое задание запускается в отдельном сеансе. Когда мы вызываем ПоместитьВоВременноеХранилище(Неопределено) без указания уникального идентификатора, система создает адрес, который существует только до следующего серверного вызова.
Рассмотрим, что происходит в коде автора. Адрес создается на сервере, передается в фоновое задание, задание помещает туда данные и завершается. Как только фоновое задание закрывает свой сеанс, данные, помещенные в хранилище без привязки к «долгоживущему» объекту (например, форме), удаляются сборщиком мусора. Когда основной сеанс пытается обратиться к этому адресу, файла там уже нет.
Для исправления ситуации необходимо привязывать адрес к УникальныйИдентификатор формы. В этом случае данные будут храниться до тех пор, пока форма открыта. Исправим серверную функцию запуска:
&НаСервере
Функция ОбработатьОжиданиеНаСервере() Экспорт
// Обязательно передаем УникальныйИдентификатор формы вторым параметром
АдресВХранилище = ПоместитьВоВременноеХранилище(Неопределено, ЭтаФорма.УникальныйИдентификатор);
мПараметры = Новый Массив;
мПараметры.Добавить(АдресВХранилище);
// Запускаем фоновое задание
ФоновоеЗадание = ФоновыеЗадания.Выполнить("Монитор.ПроизвестиФоновуюПроверку", мПараметры);
Возврат Новый Структура("Адрес, ИдентификаторЗадания", АдресВХранилище, ФоновоеЗадание.УникальныйИдентификатор);
КонецФункции
Проанализируем еще одну серьезную ошибку в исходном коде: использование метода ОжидатьЗавершенияВыполнения(10) внутри обработчика ожидания. Когда клиент вызывает серверный метод, который «ждет» 10 секунд завершения фонового задания, интерфейс пользователя полностью блокируется. Смысл использования фонового задания при этом теряется, так как пользователь все равно не может работать с программой.
Правильный подход заключается в асинхронном опросе состояния задания. Разберем по шагам, как это реализовать:
Идентификатор клиенту.Идентификатор в переменной.Посмотрим на пример реализации клиентской части:
&НаКлиенте
Процедура ОбработатьОжидание()
Если ЗначениеЗаполнено(ТекущееЗаданиеID) Тогда
СостояниеЗадания = ПроверитьСостояниеЗаданияНаСервере(ТекущееЗаданиеID);
Если СостояниеЗадания = "Завершено" Тогда
ПолучитьРезультатыИОповестить();
ТекущееЗаданиеID = Неопределено;
ИначеЕсли СостояниеЗадания = "Ошибка" Тогда
ТекущееЗаданиеID = Неопределено;
Сообщить("Фоновый мониторинг завершился с ошибкой");
КонецЕсли;
Иначе
РезультатЗапуска = ОбработатьОжиданиеНаСервере();
ТекущееЗаданиеID = РезультатЗапуска.ИдентификаторЗадания;
АдресРезультата = РезультатЗапуска.Адрес;
КонецЕсли;
КонецПроцедуры
Рассмотрим код запроса в общем модуле. Использование условия ПлановаяДатаДоставки = &ТекДата является крайне рискованным. Если в базе данных дата хранится с точностью до секунд (например, 12:00:00), а ТекущаяДата() вернет время 12:00:05, условие не сработает. Проанализируем ситуацию: просроченным считается документ, у которого плановая дата меньше текущего момента.
Также важно помнить о блокировках. Если фоновое задание будет массово изменять документы, это может привести к конфликтам, если пользователь в этот момент редактирует тот же заказ. Рекомендуется использовать БлокировкаДанных перед записью объекта. Посмотрим на исправленный фрагмент запроса и обработки:
Процедура ПроизвестиФоновуюПроверку(Адрес) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПланированиеЗакупок.Ссылка КАК Ссылка
|ИЗ
| Документ.ПланированиеЗакупок КАК ПланированиеЗакупок
|ГДЕ
| ПланированиеЗакупок.СтатусЗаказа = ЗНАЧЕНИЕ(Перечисление.СтатусЗаказаПоставки.Запланирована)
| И ПланированиеЗакупок.ПлановаяДатаДоставки < &ТекДата";
// Используем НачалоДня или ТекущуюДату в зависимости от бизнес-логики
Запрос.УстановитьПараметр("ТекДата", ТекущаяДата());
Результат = Запрос.Выполнить().Выгрузить();
Для Каждого Строка Из Результат Цикл
Попытка
Объект = Строка.Ссылка.ПолучитьОбъект();
Объект.СтатусЗаказа = Перечисления.СтатусЗаказаПоставки.Просрочена;
// Используем ОбменДанными.Загрузка = Истина, если не нужны проверки
Объект.Записать(РежимЗаписиДокумента.Запись);
Исключение
ЗаписьЖурналаРегистрации("ФоновыйМониторинг", УровеньЖурналаРегистрации.Ошибка, , , ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЦикла;
ПоместитьВоВременноеХранилище(Результат, Адрес);
КонецПроцедуры
Как справедливо заметили участники обсуждения на форуме, «изобретать велосипед» в современной разработке на 1С не стоит. Если ваша конфигурация основана на Библиотеке стандартных подсистем (БСП), для решения подобных задач следует использовать модуль ДлительныеОперации.
Преимущества БСП:
Рассмотрим пример использования БСП для запуска мониторинга:
&НаСервере
Функция ЗапуститьМониторингБСП()
ПараметрыЗадания = Новый Массив;
// БСП сама создаст адрес во временном хранилище
Результат = ДлительныеОперации.ЗапуститьВыполнение(Неопределено, "Монитор.ПроизвестиФоновуюПроверку", ПараметрыЗадания);
Возврат Результат;
КонецФункции
На клиенте при этом можно использовать стандартную процедуру ДлительныеОперацииКлиент.ОжидатьЗавершения, которая корректно обработает ожидание без блокировки интерфейса и сама вызовет оповещение по завершении.
В завершение разберем архитектурный вопрос: стоит ли вообще привязывать мониторинг просрочки к форме списка? Проанализируем ситуацию: если в выходные дни никто не откроет форму «Планирование закупок», статусы документов не обновятся. Это означает, что данные в системе будут неактуальными.
Регламентные задания — это правильный способ реализации подобных задач. Настройка регламентного задания в консоли сервера 1С позволит проверять просрочку круглосуточно, независимо от того, залогинен ли пользователь в системе. Форма же списка должна лишь визуализировать уже измененные данные (через динамический список), а для привлечения внимания пользователя можно использовать «Систему взаимодействия» (мессенджер 1С) или записывать события в специальный регистр сведений, который форма проверяет при открытии.
Таким образом, мы выяснили, что для корректной работы фоновых заданий необходимо внимательно следить за контекстом временного хранилища, избегать синхронных ожиданий на сервере и стремиться к использованию стандартных библиотек (БСП) и серверных регламентных механизмов.