Ошибка выгрузки товаров из 1С8 в WebAsyst

Обратился один из клиентов с ошибкой выгрузки товаров из 1С8 УТ 10.3 в интернет-магазин на базе Webasyst ShopScript.

Вот такие сообщения выдавала система в процессе выгрузки. Так как при выгрузке небольшой части номенклатуры выгрузка проходила нормально, то подозрение было на таймаут загрузки.

Смотрим со стороны сервера — в логах ошибка «mod_fcgid: read data timeout in 40 seconds». Похоже на данном VPS используется не только старый Apache 2.x но и к нему mod_fcgid.

Поиск в интернете дал вот такую информацию:

mod_fcgid — аналог mod_fastcgi, но для Apache 2.x. Сайт: https://fastcgi.coremail.cn/

Принцип действия FastCGI в целом таков: вместо того, чтобы запускать по одному процессу на каждый запрос, запускается тот же процесс, но как процесс-сервер. Он обрабатывает запросы клиентов по очереди, не завершаясь между запросами. Если один процесс не успевает в разумное время обрабатывать запросы — запускается еще один. Если процесс бездействует — он завершается FastCGI-диспетчером. Это вкратце.

Обилие настроек по первости поражает — легко сделать ошибку. Вкратце опишу, как настроить mod_fcgid в пределах vhost’а. Нам потребуется PHP, скомпиленный с поддержкой FastCGI. Проверяется просто: php -v должно выдавать что-то вроде PHP 5.2.5 (cgi-fcgi) (built: Dec 19 2007 12:00:49) (ключевые буковки: cgi-fcgi).

Надеюсь, собрать из исходников mod_fcgid вам проблемы не составит. Если составит — ищем веточку по сборке софта (если ее еще нет — она появится). Считаю, что собрали.

Для начала сетапим Apache. Вполне сойдет worker_mpm, prefork не нужен. Нам потребуется добавить строчки: LoadModule cgi_module modules/mod_cgi.so
LoadModule fcgid_module modules/mod_fcgid.so

(mod_fcgid.so не забываем прокинуть в каталог modules)# FCGID
IdleTimeout 30
IdleScanInterval 30
BusyTimeout 600
BusyScanInterval 60
IPCConnectTimeout 10
IPCCommTimeout 120
SocketPath /tmp/fcgi
SharememPath /tmp/fcgi/fcgid_shm
MaxProcessCount 1024
DefaultMinClassProcessCount 0
DefaultMaxClassProcessCount 32
MaxRequestsPerProcess 200
PHP_Fix_Pathinfo_Enable 1

Здесь чуть-чуть поясню, ибо параметры придется подбирать по вкусу.

IdleTimeout — это время бездействия запущенного процесса перед тем, как он будет убит. IdleScanInterval — интервал сканирования процессов на бездействие. BusyTimeout — время занятости процесса одним запросом до убиения (если процесс занят больше указанного одним запросом — он будет убит, как зависший). BusyScanInterval — интервал сканирования на зависы. IPCConnectTimeout — время ожидания соединения с выбранным не занятым процессом. Если соединиться за указанное время не удалось — выбранный процесс убивается, как подвисший, а клиенту возвращается 500. IPCCommTimeout — время ожидания первой порции данных (ответа) от процесса. Если ответа нету — также KILL+500.

SocketPath и SharememPath — это служебные пути. Первый путь — к каталогу, в котором будут создаваться сокеты для связи с процессами FastCGI. Второй — к файлу разделяемой памяти диспетчера FastCGI, который будет создан во время работы. Каталог должен существовать.

MaxProcessCount, DefaultMinClassProcessCount, DefaultMaxClassProcessCount — это управление нагрузкой. Первое — максимальное число всех процессов на весь сервер (все виртуалхосты). Второе — минимум процессов для одного приложения (например — PHP), которое будет поддерживаться. Тут я ставлю 0 — т.е. если вхост вообще не активен, пусть лучше убьются все, и не занимают бестолку память. Третье — максимум процессов для одного приложения.

MaxRequestsPerProcess. Количество запросов, после которого процесс будет убит и перезапущен. Т.е. обработали 200 запросов — будьте добры в рестарт. Меньшее число повышает надежность, большее — производительность. PHP со значениями 500 и выше в стандартной конфигурации может и не работать.

PHP_Fix_Pathinfo_Enable — тут единичка, потому что работаем корректно — надо давать PHP нормальные скриптовые пути. Не забудьте в php.ini поставить cgi.fix_pathinfo = 1.

Теперь сетапим типовой vhost:

<VirtualHost *:80>
ServerAdmin mymail@mydomain
ServerName myhost.mydomain
CustomLog /www/myhost/logs/access_log common
ErrorLog /www/myhost/logs/error_log
SuexecUserGroup myuser mygroup
DocumentRoot /www/myhost/html
<Directory /www/myhost/html>
Allow from all
AllowOverride all
Options Includes SymLinksIfOwnerMatch ExecCGI
DirectoryIndex index.php index.htm index.html default.htm default.html
AddHandler fcgid-script .php
FCGIWrapper «/www/fastcgi/myhost/php.fcgi» .php
</Directory>
</VirtualHost>

Ключевые строчки здесь: Options Includes SymLinksIfOwnerMatch ExecCGI
AddHandler fcgid-script .php
FCGIWrapper «/www/fastcgi/myhost/php.fcgi» .php

В первой обратите внимание на SymLinksIfOwnerMatch ExecCGI. Эти строчки нужны для выполнения PHP как CGI.
Во второй все просто — мы добавляем обработчик fcgid к файлам .php.
В третьей мы связываем обработчик с нашим конкретным приложением (будьте внимательны — на каждый вхост придется делать отдельное, во-первых из-за ограничений DefaultMin(Max)ProcessCount — они работают попроцессно, во-вторых из-за разграничения прав — файл php.fcgi должен быть создан с пользователем и группой, указанными в SuexecUserGroup.

Заметьте, что я выношу файлы php.fcgi за пределы дерева каталогов пользователя, чтобы он не мог получить доступ к этому файлу, например, с помощью того же PHP. Еще разумно в ext3 поставить этому файлу immutable-бит, чтобы уж точно никто его не изменил.

Теперь о файле php.fcgi. Файл php.fcgi представляет собой «враппер» для процесса PHP, на каждый vhost. Он дает нам возможность гибко манипулировать настройками каждого хоста. Пример файла:#!/bin/sh
export PHPRC=»/www/myhost/etc»
export PHP_FCGI_MAX_REQUESTS=500
export PHP_FCGI_CHILDREN=2
export TZ=»Europe/Moscow»
export LANG=»ru_RU.UTF-8″
export PWD=»/www/myhost/html»
exec /www/fastcgi/PHP/php -c /www/myhost/etc/php.ini

Тут все просто. Задаются переменные среды и запускается PHP с указанием на конфиг для данного вхоста. Отдельно обращу внимание на две вещи.

Первая — PHP_FCGI_CHILDREN. PHP — это несколько необычный FastCGI-сервер — он не просто запускается и принимает запросы, он еще и порождает дочерние процессы («потоки»), которые эти запросы обрабатывают — т.е. содержит в себе еще и собственный диспетчер процессов. Везде рекомендуется число 1, чтобы он не использовал встроенный диспетчер, однако я экспериментально для себя уяснил, что 2 слегка понижает время ответа сервера и позволяет mod_fcgid не плодить кучу процессов из-за миллисекундной занятости PHP.

Вторая вещь — переменная PWD. Такой финт ушами позволяет PHP считать, что он запущен в каталоге, указанном в значении переменной. Что самое веселое — cd, который также меняет PWD, создает OLD_PWD, который и воспринимает PHP — т.е. cd «сменить» PHP видимый каталог — не поможет. А посему и использован такой необычный подход.

Исходя из этого вносим правки:

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

Мы используем cookie-файлы для наилучшего представления нашего сайта. Продолжая использовать этот сайт, вы соглашаетесь с использованием cookie-файлов.
Принять