Почему объекты исчезают из массива во временном хранилище после выхода из серверной функции?

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

В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда данные, помещенные во временное хранилище, ведут себя непредсказуемо. Одной из самых коварных проблем является "исчезновение" элементов массива: сам массив в хранилище остается, его длина совпадает с ожидаемой, но вместо объектов типа ДокументОбъект или СправочникОбъект внутри оказываются значения Неопределено. Разберем подробно, почему это происходит и как правильно спроектировать передачу данных между серверными вызовами.

Причина проблемы: несериализуемые типы данных

Давайте проанализируем ситуацию. Тип данных ДокументОбъект является несериализуемым. Это означает, что он не может быть преобразован в последовательность байтов для передачи по сети или сохранения на диск. Он существует исключительно в оперативной памяти того рабочего процесса сервера (rphost), в котором был создан.

Рассмотрим, что происходит, когда мы выполняем следующий код:


// Ошибочный подход
&НаСервере
Функция ПолучитьАдресМассиваНовыхДокументовНаСервере()
    МассивНовыхДокументов = Новый Массив;
    НовыйДок = Документы.ЗаказПоставщику.СоздатьДокумент();
    // ... заполнение реквизитов ...
    МассивНовыхДокументов.Добавить(НовыйДок); 

    // Помещаем массив во временное хранилище
    Адрес = ПоместитьВоВременноеХранилище(МассивНовыхДокументов, Новый УникальныйИдентификатор);
    Возврат Адрес;
КонецФункции

Когда мы помещаем массив во временное хранилище, платформа 1С видит, что внутри массива находятся несериализуемые объекты. Вместо того чтобы честно сохранить состояние документа, она сохраняет лишь указатель на объект в памяти. Как только выполнение серверного вызова завершается, контекст может быть очищен, а объект удален сборщиком мусора.

Влияние кластера серверов и рабочих процессов

Выясним причину, по которой код может работать "полгода без сбоев", а затем внезапно сломаться. В простейшем варианте (один сервер, один рабочий процесс rphost, мало пользователей) объект может задержаться в памяти. Но в полноценном кластере 1С ситуация иная:

  1. Многопоточность: Следующий запрос от того же клиента (например, попытка получить данные из хранилища) может быть обработан другим рабочим процессом rphost. В памяти этого процесса объекта не существует, и вы получаете Неопределено.
  2. Динамическое обновление: При "демоническом" обновлении конфигурации кэши сбрасываются, процессы перезапускаются, что мгновенно обрывает связи с несериализуемыми данными.
  3. Режим работы клиента: В Тонком клиенте передача объектных типов невозможна в принципе. Попытка "протащить" их через хранилище — это эксплуатация недокументированной особенности, которая не гарантирует стабильности.

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

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

Рассмотрим, как переписать заполнение документов через промежуточную структуру:


&НаСервере
Функция ПолучитьАдресМассиваСтруктурНаСервере()
    МассивДанных = Новый Массив;
    
    // Вместо объекта создаем структуру с реквизитами
    ДанныеДокумента = Новый Структура;
    ДанныеДокумента.Вставить("Дата", ТекущаяДата());
    ДанныеДокумента.Вставить("Организация", Справочники.Организации.ПустаяСсылка());
    
    // Для табличных частей используем массив структур или ТаблицуЗначений
    ТЧ_Товары = Новый ТаблицаЗначений;
    ТЧ_Товары.Колонки.Добавить("Номенклатура");
    ТЧ_Товары.Колонки.Добавить("Количество");
    // ... заполнение ТЧ ...
    
    ДанныеДокумента.Вставить("Товары", ТЧ_Товары);
    МассивДанных.Добавить(ДанныеДокумента);
    
    Возврат ПоместитьВоВременноеХранилище(МассивДанных, Новый УникальныйИдентификатор);
КонецФункции

При таком подходе на стороне клиента вы получите адрес хранилища, из которого в любой момент сможете извлечь структуру и заполнить по ней ДанныеФормы или создать новый ДокументОбъект на сервере.

Решение №2: Сериализация через XDTO или XML

Если структура документа очень сложная и переписывать всё на Структуры трудозатратно, воспользуемся механизмом XDTO. Мы можем превратить объект в строку XML, которая прекрасно хранится и передается.

Разберем пример кода для сериализации:


// На сервере преобразуем объект в строку
СтрокаXML = СериализаторXDTO.ЗаписатьXML(ДокументОбъект);
МассивСтрок.Добавить(СтрокаXML);
Адрес = ПоместитьВоВременноеХранилище(МассивСтрок);

// Позже, когда нужно восстановить объект:
СтрокаИзХранилища = МассивИзХранилища[0];
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.УстановитьСтроку(СтрокаИзХранилища);
ВосстановленныйОбъект = СериализаторXDTO.ПрочитатьXML(ЧтениеXML);

Важный нюанс: СериализаторXDTO корректно работает только с теми данными, которые уже записаны в базу (имеют ссылку) или имеют четко определенную схему. Для новых, еще не записанных документов, этот метод может потребовать дополнительной настройки.

Решение №3: Использование режима Толстого клиента

Проанализируем еще один момент из обсуждения: режим работы приложения. В Толстом клиенте (управляемое приложение) объекты могут существовать на стороне клиента. Если ваша задача — быстрое исправление "внутренней" обработки для администраторов, переключение в этот режим может временно помочь. Однако для типовых конфигураций (таких как УНФ, УТ 11, ERP) это является плохой практикой, так как современные конфигурации ориентированы на Тонкий и Веб-клиент.

Как избежать "магии" в будущем?

Чтобы код работал стабильно независимо от фаз луны или настроек кластера серверов, придерживайтесь следующих правил:

Таким образом, "магия" исчезновения объектов — это лишь строгое соблюдение платформой правил работы с памятью и процессами. Переход на использование сериализуемых структур данных не только решит текущую проблему, но и сделает вашу систему готовой к масштабированию и работе в облачных сервисах.

← На главную