Работа с присоединенными файлами в системе 1С:Предприятие — это стандартная задача, однако в клиент-серверном варианте работы (SQL) пользователи часто сталкиваются с «плавающей» ошибкой: «Ошибка создания нового файла: Ошибка при вызове метода контекста (Записать)». Примечательно, что в файловой версии той же базы проблема может не проявляться, а на сервере она то возникает, то исчезает сама собой. Рассмотрим детально, почему это происходит и как окончательно устранить эту неисправность.
Проанализируем ситуацию, описанную в теме. Когда мы нажимаем кнопку «Записать» для нового файла, система выполняет ряд операций на стороне сервера приложений. Одной из ключевых причин сбоя является ограничение адресного пространства 32-битного рабочего процесса rphost. В версии платформы 8.3.10 и более ранних, если сервер 1С установлен в 32-битном исполнении, один процесс может использовать не более 2 ГБ оперативной памяти (в редких случаях до 3 ГБ с ключом /3GB).
Выясним, как именно файлы влияют на память. При передаче файла с клиента на сервер или при сохранении его в базу данных SQL, двоичные данные часто сериализуются в формат Base64. Этот формат увеличивает объем данных примерно на 33%, но при обработке внутри платформы 1С для формирования XML-пакета может потребоваться объем памяти, в 3–4 раза превышающий исходный размер файла. Если рабочий процесс rphost уже загружен другими задачами и его потребление памяти приближается к критической отметке, попытка выделить непрерывный блок памяти для записи файла заканчивается аварией метода Записать().
Многие задаются вопросом: почему в файловой базе все работает стабильно? Ответ кроется в распределении нагрузки. В файловом варианте запись файла происходит в контексте клиентского приложения, которое имеет свой собственный лимит памяти. В SQL-варианте вся тяжелая работа по кодированию и записи ложится на серверный процесс rphost, который обслуживает десятки или сотни пользователей одновременно. Фрагментация памяти на сервере приводит к тому, что даже при наличии свободного объема система не может выделить один большой кусок для записи файла.
Для устранения ошибки нам необходимо выполнить комплекс действий — от оперативной очистки памяти до долгосрочной настройки сервера.
Выключать рабочие процессы с превышением памяти. Это заставит систему автоматически создавать новые «чистые» процессы rphost вместо разросшихся старых.rphost практически не ограничен в адресном пространстве, что исключает ошибки формата Base64 при работе с файлами любого разумного размера.Иногда ошибка метода Записать() вызвана не памятью, а банальным отсутствием прав доступа. Выясним, под какой учетной записью запущена служба 1C:Enterprise Server. Обычно это USR1CV8. В SQL-варианте именно эта учетная запись должна иметь полные права на:
Temp).Если у пользователя USR1CV8 нет прав на запись в эти директории, метод контекста выдаст ошибку, так как не сможет физически разместить файл на диске перед его окончательной обработкой.
Если Журнал регистрации пуст, а ошибка продолжает возникать, нам необходимо настроить Технологический журнал (ТЖ). Это позволит увидеть системное описание ошибки, которое скрыто за общей фразой платформы. Создадим в папке конфигурации 1С (обычно C:\Program Files\1cv8\conf) файл logcfg.xml со следующим содержанием:
<config xmlns="http://v8.1c.ru/7.4/config/logcfg">
<log location="C:\LOGS\1C" history="24">
<event>
<eq property="Name" value="EXCP"/>
</event>
<property name="all"/>
</log>
</config>
После этого проанализируем созданные логи. Ищите событие EXCP (Exception). Если в описании вы увидите Out of memory или Access denied, причина станет очевидной.
Рассмотрим пример кода, который часто используется в типовых решениях для записи присоединенных файлов. Проблема может возникать при передаче данных между клиентом и сервером. Посмотрим на типовую логику:
// Пример записи файла на стороне сервера
Процедура ЗаписатьФайлНаСервере(ДанныеФайла, Владелец)
НовыйФайл = Справочники.КонтрагентыПрисоединенныеФайлы.СоздатьЭлемент();
НовыйФайл.ВладелецФайла = Владелец;
НовыйФайл.Наименование = "Скан договора";
// Здесь данные помещаются в реквизит типа ХранилищеЗначения
НовыйФайл.ФайлХранилище = Новый ХранилищеЗначения(ДанныеФайла, Новый СжатиеДанных(9));
Попытка
НовыйФайл.Записать();
Исключение
ЗаписьЖурналаРегистрации("Ошибка записи файла", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
В данном коде метод Записать() может упасть, если ДанныеФайла слишком велики для текущего состояния памяти процесса. Чтобы минимизировать риски, рекомендуем использовать хранение файлов в томах на диске вместо базы данных SQL. Это снижает нагрузку на саму СУБД и упрощает процесс записи, так как 1С просто копирует файл в файловую систему, не пытаясь упаковать его в тяжеловесный SQL-запрос.
Мы выяснили, что ошибка «Ошибка при вызове метода контекста (Записать)» в 90% случаев в SQL-версии связана с инфраструктурными ограничениями. Для стабильной работы системы присоединенных файлов необходимо следить за состоянием памяти рабочих процессов сервера 1С, использовать 64-битную платформу и обеспечивать корректные права доступа для системной учетной записи сервера. При возникновении «плавающих» сбоев всегда начинайте с анализа объема передаваемых файлов и мониторинга загрузки rphost в диспетчере задач сервера.