Почему HTTP-сервис в 1С видит старые данные из базы и как это исправить?

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

В практике разработки на платформе 1С:Предприятие часто встречается ситуация, когда внешние системы, обращаясь к HTTP-сервисам, получают неактуальные данные. Представим сценарий: пользователь меняет значение реквизита в справочнике, записывает его, и тут же инициируется HTTP-запрос к этой же базе. К удивлению разработчика, HTTP-сервис возвращает старое значение, которое было до записи. При этом, если подождать 15-20 секунд, данные "чудесным образом" обновляются. Рассмотрим подробнее, почему возникает этот эффект «запоздания» и как заставить систему отдавать актуальную информацию мгновенно.

Анализируем причину: Пул соединений и объектный кэш

Первое, что нам необходимо понять — это механизм работы сеансов HTTP-сервисов. Когда мы публикуем базу на веб-сервере (Apache или IIS), платформа использует так называемый пул соединений. Это означает, что после выполнения запроса сеанс не завершается немедленно, а "засыпает" на определенное время, ожидая следующего вызова. Это сделано для экономии ресурсов на авторизацию и инициализацию параметров сеанса.

Проанализируем ситуацию с точки зрения кэширования. В 1С существует несколько уровней кэша. Самый коварный в данном случае — объектный кэш сеанса. Когда в рамках одного сеанса (даже если он "спящий") происходит обращение к объекту через ПолучитьОбъект() или через обращение к реквизиту по ссылке (Ссылка.Реквизит), платформа считывает данные из СУБД и помещает их в память сеанса. При повторном обращении в этом же сеансе платформа, в целях оптимизации, берет данные из памяти, а не идет в SQL Server.

Если в это время данные были изменены другим пользователем (или в другом сеансе), "спящий" сеанс HTTP-сервиса об этом не узнает, пока срок жизни его внутреннего кэша не истечет или пока сеанс не будет перезапущен. Именно поэтому в отладке мы можем наблюдать, как версия данных "сама" меняется через некоторое время — просто истекает время жизни кэша.

Решение 1: Настройка файла публикации (default.vrd)

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

  1. Найдем файл публикации вашей базы default.vrd в каталоге на веб-сервере.
  2. Найдем параметр sessionMaxAge. Этот параметр определяет, сколько секунд сеанс будет храниться в пуле после завершения запроса.
  3. Если мы установим sessionMaxAge="0", платформа будет создавать новый сеанс для каждого запроса. Это гарантирует отсутствие старого кэша, но может увеличить нагрузку на сервер из-за постоянных инициализаций.

Пример настройки в файле default.vrd:


<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
        base="/MyBase"
        ib="Srvr="ServerName";Ref="BaseName";">
    <httpService name="MyService"
        alias="service.1c"
        sessionMaxAge="0"
        poolSize="10"/>
</point>

Важно: После внесения изменений в default.vrd обязательно выполните перезапуск веб-сервера, чтобы настройки вступили в силу.

Решение 2: Программная очистка кэша

Если мы не хотим полностью отключать пул сеансов (например, ради производительности), мы можем программно управлять кэшем внутри кода самого HTTP-сервиса. Рассмотрим метод ОчиститьКэшОбъектов().

Вызов этого метода в начале обработки HTTP-запроса заставляет платформу сбросить все накопленные объектные данные текущего сеанса. Выясним, как это выглядит в коде:


Функция ДанныеСправочникаГет(Запрос)
    
    // Принудительно очищаем кэш, чтобы не получить старые данные из пула
    ОчиститьКэшОбъектов();
    
    СсылкаНаЭлемент = Справочники.Номенклатура.НайтиПоКоду("001");
    
    // Теперь обращение к реквизитам гарантированно вызовет запрос к БД
    ЗначениеРеквизита = СсылкаНаЭлемент.НужныйРеквизит;
    
    // ... дальнейшая логика
    
КонецФункции

Решение 3: Использование запросов вместо объектной модели

Проанализируем разницу между обращением "через точку" и использованием объекта Запрос. В 1С запросы (Query) гораздо меньше подвержены влиянию объектного кэширования сеанса. Если вы используете конструкцию Справочники.Имя.ПолучитьОбъект(), вы почти наверняка попадете в кэш. Если же вы выбираете данные через Запрос, платформа чаще обращается напрямую к таблицам СУБД.

Для максимальной уверенности в актуальности данных в тексте запроса можно использовать конструкцию ДЛЯ ИЗМЕНЕНИЯ. Рассмотрим пример:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.НужныйРеквизит КАК Значение
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   Номенклатура.Ссылка = &Ссылка
    |ДЛЯ ИЗМЕНЕНИЯ"; // Блокировка и обход кэша

Запрос.УстановитьПараметр("Ссылка", НужнаяСсылка);
Результат = Запрос.Выполнить();

Использование ДЛЯ ИЗМЕНЕНИЯ заставляет систему игнорировать любые промежуточные кэши и извлекать самую последнюю версию данных непосредственно из транзакционного лога СУБД.

Решение 4: Особенности работы в кластере (RPHOST)

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

В этом случае, даже программная очистка кэша в коде может не сработать мгновенно. Единственным надежным способом здесь остается либо использование запроса с явным указанием ДЛЯ ИЗМЕНЕНИЯ, либо небольшая технологическая пауза перед вызовом HTTP-сервиса на стороне клиента, если бизнес-логика это позволяет.

Резюме и рекомендации

Подводя итог, если вы столкнулись с "запозданием" данных в HTTP-сервисе, рекомендуем придерживаться следующего алгоритма:

  1. Проверьте настройки публикации: Если высокая нагрузка не ожидается, установите sessionMaxAge="0" в default.vrd. Это решит 99% проблем с кэшированием.
  2. Используйте запросы: Старайтесь избегать получения объектов через ПолучитьОбъект() в коде HTTP-сервисов. Запросы к базе данных работают чище.
  3. Принудительная очистка: Добавьте ОчиститьКэшОбъектов() в начало экспортных функций модулей HTTP-сервисов.
  4. Версия данных: Если критично проверять именно факт изменения, сравнивайте ВерсияДанных объекта через запрос. Если версия в кэше не совпадает с базой, перечитывайте объект.

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

← На главную