А я таки что-то да умею.
Как оказалось, мой rc.script для PHP-FCGI кому то да пригодился кроме меня.
Posted in Программинг&Коддинг, Разное, Adminspotting | no comments |
PHP FastCGI
Наверное, как и много кто другой, я подписан на дайджест сообщений FIDO-группы fido7.ru.unix.bsd, в очередом списке активных тем оказалась тема "ngix + php-fastcgi". Полез я посмотреть. Как оказалось, это продолжение темы "Apache 2.2.4 && mod_php 5.2.0 && freebsd 6.1", где человеку посоветовали "выкинуть апач нафиг, ставить nginx+php как fastCGI".
Не буду косаться темы перехода с Apache на nginx, потому как клоню я не к тому. Прочтя там же сообщение от некого Alex'а Ivanov'а, вспомнил, что у меня у самого не дописан толком скрипт старта PHP как FastCGI-приложения.
Нет. Он, конечно, рабочий, но вот не до конца реализовано в нем все, что задумано и есть некоторые недочеты. Сообственно, вот он, знакомтесь:
/usr/local/etc/rc.d/php_fastcgi:2 #
3
4 # PROVIDE: php_fastcgi
5 # REQUIRE: DAEMON
6 # BEFORE: LOGIN
7 # KEYWORD: shutdown
8
9 . /etc/rc.subr
10
11 name="php_fastcgi"
12 rcvar=`set_rcvar`
13
14 load_rc_config $name
15
16 : ${php_fastcgi_enable="NO"}
17 : ${php_fastcgi_user="www"}
18 : ${php_fastcgi_bindaddr="127.0.0.1"}
19 : ${php_fastcgi_bindport="9000"}
20 : ${php_fastcgi_children="5"}
21 : ${php_fastcgi_max_requests="1000"}
22
23 export PHP_FCGI_CHILDREN=${php_fastcgi_children}
24 export PHP_FCGI_MAX_REQUESTS=${php_fastcgi_max_requests}
25
26 command="/usr/local/bin/php-cgi"
27 command_args="-q -b ${php_fastcgi_bindaddr}:${php_fastcgi_bindport} &"
28
29 load_rc_config $name
30
31 run_rc_command "$1"
По сути, сам скрипт - вариация на тему FreeBSD rc-скрипта. Идея не моя, а честно подсмотрена у Alexey'я N. Kovyrin'а из его поста о настройке связки nginx+php, а я лиш перенес его в rc.d, понавесив сверху правельных рюшечек из rc.subr(8) и добавив возможность его конфигурации по-пацански из /etc/rc.conf.d/php_fastcgi.
Так вот, собственно о том, что меня в нем не устраивает.
То что он матерится при стопе:Stopping php_fastcgi.
kill: 56598: No such process
kill: 56599: No such process
kill: 56600: No such process
kill: 56601: No such process
kill: 56602: No such process
И то, что в нем отсутвует ограничение на переменные среды в которой запускаться сам php-cgi.
В принципе - обе проблемы имеют весьма очерченую суть и известное место, "откуда ростут ноги".
По поводу остановки процессов.
Как говорится в документации к rc.subr(8), если run_rc_command используется с параметром stop, то $sig_stop посылается всем процессам. И, судя по нутрям самого /etc/rc.subr, не просто killall(1), а каждому процессу по отдельности. А тут же имеем случай, когда родительский процесс при завершении завершает сначала дочерние, что и выливается в фактической отсутвие порцесса с pid из списка, которые необходимо застопить. При этом в самом rc-скрипте можно сказазать, что работать с pid'ом из $pidfile. Проблема в том, что некому этот пид-файл создать:
Usage: php [-q] [-h] [-s] [-v] [-i] [-f <file>]
php <file> [args...]
-a Run interactively
-b <address:port>|<port> Bind Path for external FASTCGI Server mode
-C Do not chdir to the script's directory
-c <path>|<file> Look for php.ini file in this directory
-n No php.ini file will be used
-d foo[=bar] Define INI entry foo with value 'bar'
-e Generate extended information for debugger/profiler
-f <file> Parse <file>. Implies `-q'
-h This help
-i PHP information
-l Syntax check only (lint)
-m Show compiled in modules
-q Quiet-mode. Suppress HTTP Header output.
-s Display colour syntax highlighted source.
-v Version number
-w Display source with stripped comments and whitespace.
-z <file> Load Zend extension <file>.
Полез я по этому поводу в исходнки самого PHP (если интересно 5.2.0) -- авось есть какая недокументровная фича по поводу пидфайла для fcgi-режима. Особо не надеясь, и не растроившись ничего не найдя, отдуши посмеялся:
php-5.2.0/Zend/zend_config.nw.h:#define HAVE_GETPID 1
php-5.2.0/Zend/Zend.m4:AC_CHECK_FUNCS(memcpy strdup getpid kill strtod strtol finite fpclass)
php-5.2.0/Zend/zend_alloc.c:#if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
php-5.2.0/Zend/zend_alloc.c: kill(getpid(), SIGSEGV);
php-5.2.0/Zend/ChangeLog: Fix another stupid mistake.
php-5.2.0/Zend/ChangeLog: Fix stupid mistake that only affected interactive mode.
php-5.2.0/Zend/ChangeLog: * zend_list.c: Fix a stupid bug (from stefan@roehri.ch)
php-5.2.0/Zend/ChangeLog: * zend-parser.y: I'm on a roll. Fix a nasty yet stupid AiCount bug
php-5.2.0/Zend/ChangeLog: * Fix a stupid bug - forgot to pass CLS_C to some compiler function. For some reason
Вероятность встретить в исходниках PHP слово pid в составе корня слова stupid предшествующему словам mistake или bug выше, нежели обособленно само слово (5 против 4).
Ну что ж -- будем своими силами решать. Костылем.
29 pidfile="/var/run/${name}.pid"
30 start_postcmd="ps -U ${php_fastcgi_user} -o 'pid,command'|grep ${command}|head -1|awk -- '{print \$1}' > ${pidfile}"
31
Т. е. мы сами создаем пидфайл и пишем в него процесс, который ps(1) покажет выше всех, тот у которого меньший pid (у меня по крайней мере так и было). Разумно, предположить, что это и есть родитель.
Один минус - если удалить пидфайл вручную rc.subr(1) будет считать, что процесс уже остановлен, со всеми вытекающимипоследствиями. Но это скорей не проблемы скрипта, а проблемы рук, которые так сделают — ими управляет тупая голова.
Окружение
А ничего мудрить нового не будем, и воспользуемся все тем же старым-добрым env(1), так же как и в оригинальном скрипте у Alexey'я N. Kovyrin'а, с небольшими доработками:
32 : ${php_fastcgi_allowed_env=""}
33 _allowed_env="ORACLE_HOME PATH USER PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"
34 _allowed_env="${_allowed_env} ${php_fastcgi_allowed_env}"
35 start_precmd="${name}_start_precmd"
36 php_fastcgi_start_precmd()
37 {
38 export USER=${php_fastcgi_user}
39 E=
40 for i in ${_allowed_env}; do
41 eval _val="\$$i"
42 if [ "${_val}_x" != "_x" ]; then
43 eval _add="$i=$_val"
44 E="${E} ${_add}"
45 fi
46 done
47 command="env - ${E} ${command}"
48 }
49
| Variable | Value |
|---|---|
| PATH | /home/talmuth/personal/bin:/home/talmuth/personal/lib/ruby/gems/bin:/home/talmuth/bin:/sbin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/games |
| USER | www |
| PHP_FCGI_CHILDREN | 5 |
| PHP_FCGI_MAX_REQUESTS | 1000 |
как видим - есть нам вселенское счастье.
Разложим все по своим местам
В результате всех самоистязаний получаем простой и рабочий скриптик:
2 #
3
4 # PROVIDE: php_fastcgi
5 # REQUIRE: DAEMON
6 # BEFORE: LOGIN
7 # KEYWORD: shutdown
8
9 . /etc/rc.subr
10
11 name="php_fastcgi"
12 rcvar=`set_rcvar`
13
14 load_rc_config $name
15
16 : ${php_fastcgi_enable="NO"}
17 : ${php_fastcgi_user="www"}
18 : ${php_fastcgi_bindaddr="127.0.0.1"}
19 : ${php_fastcgi_bindport="9000"}
20 : ${php_fastcgi_children="5"}
21 : ${php_fastcgi_max_requests="1000"}
22 : ${php_fastcgi_allowed_env=""}
23
24 export PHP_FCGI_CHILDREN=${php_fastcgi_children}
25 export PHP_FCGI_MAX_REQUESTS=${php_fastcgi_max_requests}
26
27 command="/usr/local/bin/php-cgi"
28 command_args="-q -b ${php_fastcgi_bindaddr}:${php_fastcgi_bindport} &"
29 pidfile="/var/run/${name}.pid"
30
31 _allowed_env="ORACLE_HOME PATH USER PHP_FCGI_CHILDREN PHP_FCGI_MAX_REQUESTS FCGI_WEB_SERVER_ADDRS"
32 _allowed_env="${_allowed_env} ${php_fastcgi_allowed_env}"
33
34 start_precmd="${name}_start_precmd"
35 start_postcmd="ps -U ${php_fastcgi_user} -o 'pid,command'|grep ${command}|head -1|awk -- '{print \$1}' > ${pidfile}"
36
37 php_fastcgi_start_precmd()
38 {
39 export USER=${php_fastcgi_user}
40 E=
41 for i in ${_allowed_env}; do
42 eval _val="\$$i"
43 if [ "${_val}_x" != "_x" ]; then
44 eval _add="$i=$_val"
45 E="${E} ${_add}"
46 fi
47 done
48 command="env - ${E} ${command}"
49 }
50
51 load_rc_config $name
52
53 run_rc_command "$1"
Который в text/plain можно скачать отсюда
Have fun!!!
Posted in Программинг&Коддинг, Adminspotting, Софт | 2 comments |