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