В современной разработке на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с требованиями системы «Автоматизированная проверка конфигураций» (АПК). Одно из таких требований — использование асинхронных методов вместо синхронных. На первый взгляд это кажется странным, особенно когда речь идет о серверном коде. В данной статье мы подробно разберем, зачем нужна асинхронность на сервере, как правильно реализовать проверку файла и каким образом передать огромные лог-файлы на клиент, не вызвав переполнения оперативной памяти.
Проанализируем ситуацию: разработчик пишет код для проверки файла на сервере, используя привычный метод Файл.Существует() или НайтиФайлы(). Однако при проверке через АПК система выдает предупреждение. Почему так происходит? Рассмотрим основные причины:
НайтиФайлыАсинх() гарантирует, что код будет соответствовать современным стандартам разработки.Разберем по шагам, как переписать старый синхронный код под требования АПК. Вместо создания объекта Файл и вызова метода Существует(), мы будем использовать глобальный метод НайтиФайлыАсинх(). Посмотрим на пример реализации на стороне сервера:
// Пример асинхронной проверки на сервере (в контексте серверной процедуры)
&НаСервере
Функция ПроверитьНаличиеЛогаНаСервере(ПолныйПутьКФайлу)
// Вместо синхронного НайтиФайлы() используем асинхронный аналог
// На сервере мы можем использовать оператор Ждать, чтобы дождаться результата
Обещание = НайтиФайлыАсинх(ПолныйПутьКФайлу);
МассивФайлов = Ждать Обещание;
Если МассивФайлов.Количество() > 0 Тогда
Возврат Истина;
Иначе
Возврат Ложь;
КонецЕсли;
КонецФункции
Проанализируем этот код. Оператор Ждать приостанавливает выполнение текущего потока до тех пор, пока Обещание (результат работы НайтиФайлыАсинх) не будет выполнено. Это позволяет писать код в «линейном» стиле, при этом формально соблюдая требования асинхронности.
Часто разработчики совершают ошибку, пытаясь вызвать ЗапуститьПриложение() непосредственно в серверном коде, чтобы открыть лог-файл. Выясним причину, почему это не работает. Когда код выполняется на сервере, команда запуска приложения срабатывает в контексте операционной системы сервера, часто под служебной учетной записью (например, USR1CV8). Пользователь на своем компьютере ничего не увидит, а на сервере может зависнуть «фантомный» процесс текстового редактора.
Правильный алгоритм действий всегда должен быть следующим:
Рассмотрим подробнее, как реализовать этот механизм. Для этого нам понадобится взаимодействие между серверной и клиентской частью формы.
&НаКлиенте
Асинх Процедура ПроверитьИОткрытьЛог(Команда)
РезультатПроверки = ПроверитьНаличиеЛогаНаСервере(ПутьКФайлу);
Если РезультатПроверки.ФайлНайден Тогда
// Получаем файл с сервера во временное хранилище
АдресХранилища = ПолучитьФайлВХранилище(ПутьКФайлу);
// Получаем файл из хранилища на локальный диск клиента
ОписаниеФайла = Новый ОписаниеПередаваемогоФайла(ПутьКФайлу);
ПолученныеФайлы = Ждать ПолучитьФайлыАсинх(АдресХранилища, , Истина);
Если ПолученныеФайлы <> Неопределено Тогда
// Теперь файл на клиенте, его можно открыть
ЗапуститьПриложение(ПолученныеФайлы[0].Имя);
КонецЕсли;
Иначе
Сообщить("Файл лога не найден на сервере.");
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция ПолучитьФайлВХранилище(ПолныйПутьКФайлу)
ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ПолныйПутьКФайлу);
Возврат ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, ЭтаФорма.УникальныйИдентификатор);
КонецФункции
Разберем ситуацию, упомянутую в обсуждении: что делать, если лог-файл весит несколько гигабайт? Использование Новый ДвоичныеДанные(Путь) загрузит весь файл в оперативную память сервера. Если несколько пользователей одновременно попытаются открыть такие логи, сервер может упасть с ошибкой Out of Memory.
Для решения этой проблемы проанализируем современные возможности платформы по потоковой обработке данных. Начиная с версии 8.3.9, в 1С доступны объекты ЧтениеДанных и ФайловыйПоток.
Если файл слишком велик, вместо передачи всего файла целиком, лучше прочитать только его «хвост» (последние несколько тысяч строк) и передать только этот фрагмент. Посмотрим, как это реализовать:
&НаСервере
Функция ПрочитатьПоследниеСтрокиЛога(ПутьКФайлу, РазмерБуфераКБ = 100)
ФайлЛога = Новый Файл(ПутьКФайлу);
РазмерФайла = ФайлЛога.Размер();
// Если файл меньше буфера, читаем целиком
// Если больше — отступаем от конца
Смещение = Макс(0, РазмерФайла - (РазмерБуфераКБ * 1024));
Поток = Новый ФайловыйПоток(ПутьКФайлу, РежимОткрытияФайла.Открыть, ДоступКФайлу.Чтение);
Поток.Перейти(Смещение, РежимПеремещенияВПотоке.Начало);
Чтение = Новый ЧтениеДанных(Поток);
Результат = Чтение.ПрочитатьСимволы(); // Читаем до конца потока
Поток.Закрыть();
Возврат ПоместитьВоВременноеХранилище(Результат, ЭтаФорма.УникальныйИдентификатор);
КонецФункции
Важный момент: При работе с потоками мы не загружаем файл в память целиком. Мы перемещаем указатель чтения в нужную позицию и считываем только требуемый фрагмент. Это позволяет безопасно обрабатывать логи любого объема.
Подводя итог нашему анализу, сформулируем основные правила работы с файлами на сервере в современных конфигурациях:
НайтиФайлыАсинх, КопироватьФайлАсинх), если ваша конфигурация проходит проверку АПК.Ждать. Это сохраняет логику кода понятной и линейной.ЗапуститьПриложение на сервере для взаимодействия с пользователем.ФайловыйПоток) для извлечения только актуальной информации, вместо загрузки всего файла через ДвоичныеДанные.Следуя этим правилам, вы не только успешно пройдете автоматизированную проверку конфигурации, но и создадите отказоустойчивое решение, которое не будет потреблять лишние ресурсы сервера при работе с большими объемами данных. Для дополнительного контроля качества кода можно использовать инструмент для анализа конфигураций и расширений на наличие ошибок.