Почему сохранение Excel-файла на сервере 1С зависает и как это исправить?

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

При работе с платформой 1С:Предприятие версии 8.3 (и старше) разработчики часто сталкиваются с необходимостью формирования файлов различных форматов, включая Microsoft Excel. Хотя для создания табличных документов в 1С существуют встроенные механизмы, в некоторых случаях удобнее использовать прямой COM-объект Excel для сложных отчетов или взаимодействия с уже существующими шаблонами. Однако при попытке выполнения операций с COM-объектом Excel на сервере 1С, особенно связанных с сохранением файлов, мы можем столкнуться с неожиданными зависаниями и непредсказуемым поведением. В этой статье мы подробно разберем, почему возникают такие проблемы и как их эффективно решить.

Анализируем проблему: зависание при серверном создании и сохранении Excel-файла

Давайте рассмотрим типичную ситуацию, описанную в исходной теме форума. Разработчик пытается создать и сохранить Excel-файл из конфигурации 1С:Зарплата и Управление Персоналом 2.5 (или любой другой конфигурации на платформе 8.3, использующей управляемые формы) на сервере 1С. При этом, при запуске той же операции в файловом варианте базы (т.е. на клиентской машине, где и запускается 1С), все работает корректно: Excel-файл создается и сохраняется без проблем.

Однако при выполнении кода на сервере 1С мы наблюдаем следующее:

  1. Программа не вылетает, не выдает ошибок и не завершает свое действие. Процесс “крутится” неопределенное время.
  2. Если принудительно прервать выполнение, например, через консоль 1С, сеанс и соединение остаются активными, а последняя активность постоянно обновляется до текущего времени. При попытке удалить такой сеанс он восстанавливается после обновления данных в консоли.
  3. Даже при добавлении блоков Попытка...Исключение в код создания COM-объекта, добавления книги и сохранения файла, никаких ошибок не возникает. Процесс просто не заканчивается, а исключения не перехватываются.

Это явно указывает на то, что Excel или операционная система чего-то ожидают, но не получают, что приводит к зависанию процесса 1С-сервера.

Ключевые причины проблемы и эффективные решения

Проанализируем основные причины, которые приводят к описанным зависаниям, и предложим конкретные шаги для их устранения.

1. Различие контекста выполнения: Клиент против Сервера

Первостепенная причина кроется в фундаментальном различии между клиентским и серверным окружениями 1С:Предприятия.

  1. Клиентское выполнение: Когда вы запускаете 1С в файловом режиме или выполняете код на клиенте в клиент-серверном варианте, все действия происходят под учетной записью интерактивного пользователя, который вошел в операционную систему. У этого пользователя есть рабочий стол, активная сессия, он может видеть диалоговые окна и имеет определенные права доступа к файловой системе и COM-обпользователям.
  2. Серверное выполнение: Сервер 1С (процесс ragent.exe, rmngr.exe, rphost.exe) обычно запускается от имени специальной сервисной учетной записи (например, "Локальная система" или выделенной учетной записи типа "USR1CV8"). Эта учетная запись не имеет интерактивного рабочего стола, не может отображать диалоговые окна и имеет свой собственный набор прав доступа, которые могут сильно отличаться от прав интерактивного пользователя.

Microsoft Office, и Excel в частности, изначально не предназначен для работы в серверном окружении без интерактивного пользователя. Он может пытаться отобразить различные диалоговые окна (например, "Файл уже существует, заменить?", "Сохранить изменения перед закрытием?", "Проблемы совместимости") или ожидать доступа к каким-либо ресурсам, доступным только интерактивному пользователю. На сервере эти диалоги просто не появляются, и Excel зависает, ожидая ответа, который никогда не получит.

Решение 1: Перенос формирования Excel на клиентскую сторону

Самым простым и надежным решением является перенос всего процесса создания и сохранения Excel-файла на клиентскую сторону. Этот подход был успешно применен в обсуждаемой теме и является рекомендуемым Microsoft для интерактивных сценариев.

  1. Как это работает: При выполнении кода на клиенте, COM-объект Excel запускается на компьютере пользователя. Он работает под учетной записью пользователя, имеет доступ к его файловой системе и может отображать все необходимые диалоговые окна. Это устраняет проблемы с контекстом безопасности и отсутствием интерактивности.
  2. Реализация:
    • Если ваша процедура находится в общем модуле, убедитесь, что она помечена как &НаКлиенте или вызывается из клиентской процедуры.
    • Если данные для отчета формируются на сервере, их необходимо передать на клиент. Это можно сделать, например, с помощью таблиц значений, структур или объектов типа СписокЗначений, передавая их как параметры клиентской функции.

Пример адаптации кода (на основе сообщения 9):

Предположим, что данные ДанныеДляКонсоли формируются на сервере. Мы можем передать их на клиент и уже там выполнить формирование Excel.


// В серверной процедуре (или в обработчике команды на управляемой форме)
&НаСервере
Функция ПолучитьДанныеДляОтчета()
    // Здесь формируем необходимые данные на сервере
    ТаблицаДанных = Новый ТаблицаЗначений;
    ТаблицаДанных.Колонки.Добавить("ФИО");
    // Пример заполнения
    Для Каждого СтрокаТЗ Из Справочники.ФизическиеЛица.Выбрать() Цикл
        НоваяСтрока = ТаблицаДанных.Добавить();
        НоваяСтрока.ФИО = СтрокаТЗ.Наименование;
    КонецЦикла;
    Возврат ТаблицаДанных;
КонецФункции

// В клиентской процедуре
&НаКлиенте
Процедура КомандаСохранитьExcel(Команда)
    ШырПуть = "";
    // Открываем диалог выбора файла на клиенте
    Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Сохранение);
    Диалог.Заголовок = "Выберите место для сохранения файла Excel";
    Диалог.Фильтр = "Файлы Excel (*.xlsx)|*.xlsx";
    Диалог.ПолноеИмяФайла = "Отчет_" + Формат(ТекущаяДата(), "ДФ=yyyyMMdd_HHmmss") + ".xlsx";

    Если Диалог.Выбрать() Тогда
        ШырПуть = Диалог.ПолноеИмяФайла;
    Иначе
        Возврат; // Пользователь отменил сохранение
    КонецЕсли;

    // Получаем данные с сервера
    ДанныеДляКонсоли = ПолучитьДанныеДляОтчета(); 

    Попытка
        Excel = Новый COMОбъект("Excel.Application");
    Исключение
        ВызватьИсключение("COMОбъект(Excel) не создан. Возможно, Excel не установлен на компьютере!");
    КонецПопытки;

    // Добавляем эту строку, чтобы Excel не выводил диалоговые окна
    Excel.DisplayAlerts = 0; 

    Попытка
        Книга = Excel.WorkBooks.Add;
    Исключение
        Excel.Quit(); // Корректно закрываем Excel в случае ошибки
        ВызватьИсключение("COMОбъект(Excel) создан, но книга НЕ ДОБАВЛЕНА!");
    КонецПопытки;

    Лист = Книга.WorkSheets(1);
    Лист.Cells(1, 1).Value = "ФИО";
    СтрНом = 2;
    Для Каждого СтрКон Из ДанныеДляКонсоли Цикл
        Лист.Cells(СтрНом, 1).Value = СтрКон.ФИО;
        СтрНом = СтрНом + 1;
    КонецЦикла;

    Попытка
        Книга.SaveAs(ШырПуть);
        Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
        Excel.Quit();
        Сообщить("Файл успешно сохранен: " + ШырПуть, СтатусСообщения.Информация);
    Исключение
        Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
        Excel.Quit();
        Сообщить("ОШИБКА сохранения файла!", СтатусСообщения.ОченьВажное);
        Ошибка = ОписаниеОшибки();
        ЗаписьЖурналаРегистрации("ОШИБКА сохранения файла!", УровеньЖурналаРегистрации.Ошибка,,, Ошибка);
    КонецПопытки;
КонецПроцедуры

Обратите внимание, что в данном примере мы добавили вызов Excel.DisplayAlerts = 0; перед работой с книгой. Это вторая важная часть решения.

2. Подавление интерактивных сообщений Excel

Как мы уже выяснили, одной из основных причин зависаний являются скрытые диалоговые окна Excel, которые сервер не может отобразить и обработать. Для решения этой проблемы существует специальное свойство COM-объекта Excel.

  1. Свойство Excel.DisplayAlerts: Это свойство управляет отображением предупреждений и сообщений Excel. Если установить его в 0 (или Ложь в контексте 1С), Excel не будет выводить никаких диалоговых окон, а вместо этого будет принимать действия по умолчанию.
  2. Применение: Установите Excel.DisplayAlerts = 0; сразу после успешного создания COM-объекта Excel (Новый COMОбъект("Excel.Application")).

Пример кода из сообщения 9 с учетом DisplayAlerts:


&НаСервере // Предположим, вы все же решили попробовать на сервере
Процедура СохрФайлНаСервере(ШырПуть, ДанныеДляКонсоли)

    Попытка
        Excel = Новый COMОбъект("Excel.Application");
    Исключение
        // Здесь можно добавить более детальную обработку ошибки, 
        // например, запись в журнал регистрации и вывод сообщения пользователю через клиентскую процедуру.
        ВызватьИсключение("COMОбъект(Excel) не создан. Возможно, Excel не установлен на компьютере!");
    КонецПопытки;

    // *** ВАЖНО: Отключаем вывод всех предупреждений и диалоговых окон Excel ***
    Excel.DisplayAlerts = 0; 

    // Создание книги
    Попытка
        Книга = Excel.WorkBooks.Add;
    Исключение
        Excel.Quit(); // Корректно закрываем Excel
        ВызватьИсключение("COMОбъект(Excel) создан, но книга НЕ ДОБАВЛЕНА!");
    КонецПопытки;

    Лист = Книга.WorkSheets(1);
    Лист.Cells(1, 1).Value = "ФИО";
    СтрНом = 2;
    Для Каждого СтрКон Из ДанныеДляКонсоли Цикл
        Лист.Cells(СтрНом, 1).Value = СтрКон.ФИО;
        СтрНом = СтрНом + 1;
    КонецЦикла;

    // Сохранение книги
    Попытка
        Книга.SaveAs(ШырПуть);
        Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
        Excel.Quit();
        // На сервере нельзя вызывать Сообщить(). Нужно передать информацию на клиент.
        // Сообщить("Файл успешно сохранен: " + ШырПуть,СтатусСообщения.Информация); 
    Исключение
        Книга.Close(Ложь); // Закрываем книгу без запроса сохранения изменений
        Excel.Quit();
        // Аналогично, на сервере нельзя вызывать Сообщить().
        // Сообщить("ОШИБКА сохранения файла!", СтатусСообщения.ОченьВажное); 
        Ошибка = ОписаниеОшибки();
        ЗаписьЖурналаРегистрации("ОШИБКА сохранения файла!", УровеньЖурналаРегистрации.Ошибка,,, Ошибка);
        ВызватьИсключение("ОШИБКА сохранения файла! " + Ошибка); // Пробрасываем ошибку на клиент
    КонецПопытки;
КонецПроцедуры

Даже с Excel.DisplayAlerts = 0, работа с Excel на сервере все еще не является идеальным решением из-за других потенциальных проблем, которые мы рассмотрим далее.

Дополнительные аспекты и рекомендации при работе с Excel на сервере

Хотя перенос формирования Excel на клиентскую сторону и отключение сообщений с помощью Excel.DisplayAlerts = 0 являются основными решениями, существуют и другие важные аспекты, которые следует учитывать, если вы все же решаете (или вынуждены) использовать COM-объект Excel на сервере 1С.

1. Контекст безопасности и права доступа DCOM

Как уже упоминалось, сервер 1С работает под определенной системной или сервисной учетной записью. Эта учетная запись должна иметь:

  1. Права на файловую систему: Убедитесь, что учетная запись, под которой запущен процесс rphost.exe (рабочий процесс сервера 1С), имеет полные права на чтение и запись в каталоге, куда сохраняется Excel-файл. Сисадмин должен это проверить. Это касается не только самой папки, но и всего пути к ней.
  2. Права DCOM для Microsoft Excel Application: Это очень важный аспект. Excel является COM-сервером, и его запуск из другой учетной записи (сервер 1С) требует корректной настройки DCOM (Distributed COM).
    1. Откройте оснастку "Службы компонентов" (dcomcnfg).
    2. Перейдите к "Службы компонентов" -> "Компьютеры" -> "Мой компьютер" -> "Настройка DCOM".
    3. Найдите "Microsoft Excel Application".
    4. Вызовите свойства объекта и на вкладках "Безопасность" (Security) и "Идентификация" (Identity) настройте необходимые разрешения:
      • Запуск и активация: Добавьте учетную запись сервера 1С (и, возможно, группу "Все" или "Пользователи") с разрешениями на локальный и удаленный запуск и активацию.
      • Разрешения на доступ: Аналогично предоставьте права на локальный и удаленный доступ.
      • Идентификация: Здесь можно указать, под какой учетной записью будет запускаться Excel. Часто выбирают "Пользователь, запускающий приложение" (The launching user) или указывают конкретную учетную запись, которая имеет все необходимые права (например, интерактивного пользователя или специально созданного). Однако, будьте осторожны, так как установка конкретной учетной записи может привести к проблемам безопасности и конфликтам.

    Некорректные настройки DCOM часто приводят к ошибкам типа "COM-объект не создан" или к невозможности взаимодействия с уже созданным объектом.

  3. Профиль пользователя: COM-серверы, такие как Excel, могут нуждаться в доступе к профилю пользователя для чтения настроек, временных файлов и т.д. Для сервисных учетных записей профиль пользователя по умолчанию может быть ограничен. Это может проявляться в виде ошибок, связанных с доступом к папкам типа "Рабочий стол" или "Мои документы", которые Excel может пытаться использовать по умолчанию.

2. Ресурсы и стабильность: Почему Microsoft не рекомендует Excel на сервере

Microsoft официально не рекомендует использовать COM-автоматизацию Office (включая Excel) на сервере по нескольким причинам:

  1. Нестабильность и утечки памяти: Office приложения не предназначены для работы как серверные компоненты. Они могут зависать, вызывать исключения, которые невозможно перехватить, или иметь утечки памяти, особенно при множественных одновременных запросах.
  2. Масштабируемость: Каждый экземпляр Excel потребляет значительные ресурсы (память, процессор). При большом количестве пользователей или частых запросах сервер может быстро исчерпать ресурсы.
  3. Безопасность: Запуск Office-приложений от имени сервисной учетной записи может создавать уязвимости, так как эти приложения могут выполнять произвольный код и потенциально быть использованы для повышения привилегий или атак.
  4. Лицензирование: Лицензии на Microsoft Office обычно предназначены для интерактивных пользователей, а не для серверной автоматизации. Использование Office на сервере для автоматизации может нарушать условия лицензионного соглашения.

3. Корректное завершение процессов Excel

Очень важно после каждой операции с Excel корректно завершать все связанные процессы. В приведенном коде используются Книга.Close() и Excel.Quit(), что является правильным подходом. Однако, в случае возникновения ошибок до вызова Quit(), экземпляры Excel могут оставаться висеть в фоновых процессах. Это приводит к накоплению "мертвых" процессов Excel, которые продолжают потреблять ресурсы сервера. Чтобы избежать этого, можно:

  1. Использовать блоки Попытка...Исключение...КонецПопытки: Оборачивайте операции с Excel в такие блоки и в секции Исключение всегда вызывайте Книга.Close(Ложь) и Excel.Quit().
  2. Освобождение COM-объектов: В 1С объекты COM-объектов обычно освобождаются автоматически при выходе из области видимости, но для большей надежности можно использовать метод COMОбъект.Disconnect() (доступен для некоторых COM-объектов) или явно устанавливать переменные в Неопределено.
  3. Мониторинг процессов: Регулярно проверяйте наличие "висящих" процессов EXCEL.EXE на сервере и, при необходимости, принудительно их завершайте (хотя это является временным решением, а не устранением причины).

4. Альтернативные решения для серверного формирования XLSX

Если вам критически важно формировать Excel-файлы на сервере без интерактивного участия и вы хотите избежать проблем с COM-автоматизацией Microsoft Office, рассмотрите альтернативные решения:

  1. Библиотеки для работы с XLSX: Существуют специализированные библиотеки (например, OpenXML SDK для .NET, различные библиотеки для работы с XLSX-форматом в других языках программирования, которые можно обернуть в внешние компоненты 1С). Эти библиотеки позволяют создавать, читать и модифицировать файлы формата XLSX (фактически, это архивы XML) без запуска самого Microsoft Excel. Это самый надежный способ для серверного использования.
  2. Использование внешних компонентов или веб-сервисов: Можно создать отдельный внешний компонент для 1С или веб-сервис, который будет работать с такими библиотеками на стороне сервера и предоставлять 1С функциональность по созданию XLSX.

Заключение

Проблема зависания при сохранении Excel-файла на сервере 1С в большинстве случаев сводится к различиям в контексте выполнения между клиентом и сервером, а также к интерактивным запросам, которые Excel пытается отобразить. Наиболее простым и надежным решением является перенос формирования Excel-файлов на клиентскую сторону и использование свойства Excel.DisplayAlerts = 0. Если же серверное использование Excel является неизбежным, необходимо уделить пристальное внимание настройкам безопасности DCOM, правам доступа файловой системы и корректному завершению всех процессов Excel. Для наиболее стабильной и масштабируемой работы на сервере рекомендуется использовать специализированные библиотеки для работы с форматом XLSX, не требующие наличия установленного Microsoft Office.

← На главную