Anonymоus
26-06-2019, 18:07
Приветствую уважаемых форумчан.
Есть скрипт — загрузчик, который стартует портабельную сборку nginx + php + mysql + доп. модули, он рассчитан на запуск как от юзера, так и в качестве сервиса (например, через nssm). Хотелось бы организовать пул процессов интерпретатора php-cgi на разных портах, и такая возможность в принципе есть через конфиг бэкенда в nginx, но для отслеживания возможных падений (а у php это не столько редко случается) и перезапуска конкретного экземпляра мне нужен PID запущенного процесса. Я знаю о возможности запуска через wmic process call create с получением PID дочернего процесса, но тут есть проблема: я запускаю через hidcon, соответственно получаю PID hidcon-а, а не php-cgi.
Собственно, вопрос: как запустить без видимого окна и получить PID? Или каким ещё образом можно отслеживать одинаковые процессы, запущенные с разными аргументами?
@Echo Off
:: Portable nginx+php+mysql for Windows
:: Inquisitor, 2013-2019
:: nginx 1.17.1
:: php 7.2.19 + composer
:: mysql 5.7.23
CD /D "%~dp0"
:: Лог работы скрипта
Set LogFile=%~dpn0.log
:: Формат даты в логе
Set TimestampFormat=[%%Date%% %%Time:~,8%%]
:: Периодичность проверки запроса на отключение и перезапуска процессов при падении, секунды
Set WatcherTimeout=10
:: Обрабатываем команду на выключение
If /I "%~1"=="shutdown" (
If Exist "%~dp0.loader.lock" (
Call :Log Received termination signal, shutting down
Del "%~dp0.loader.lock" 2>nul
) Else (
Call :Log [WARNING] Received termination signal, server not started
)
Exit /B
)
:: Обрабатываем запуск сервиса
If /I "%~1"=="service" (
Call Echo.>>"%LogFile%"
Call :Log Loader started as service
GoTo :service
)
:: Перезапускаем себя как скрытый процесс, если запущено без аргументов
If "%~1"=="" (
Start "" "%~dp0tools\hidcon" %~nx0 restart_hidden
Call Echo.>>"%LogFile%"
Call :Log Loader started
Exit
)
:service
:: Сохраняем оригинальный path
Set OSPath=%Path%
:: Добавляем пути к бинарникам в системный path для этого скрипта и дочерних процессов
Set Path=%~dp0tools;%~dp0nginx;%~dp0php;%~dp0mysql\bin
:: Добавляем модули
:: FFMpeg 4.1.3
Set Path=%Path%;%~dp0modules\ffmpeg
:: ImageMagick 6.9.3 (php7)
Set Path=%Path%;%~dp0modules\imagick-php7\ImageMagick
Set LOCALAPPDATA=%~dp0modules\imagick-php5
:: Меняем системный temp на наш
Set Temp=%~dp0\tmp
:: Добавляем системный path с низшим приоритетом
Set Path=%Path%;%OSPath%
:: Обрабатываем запуск консоли в рабочем окружении (Composer \ RIOX)
If /I "%~1"=="console" (
PushD nginx\wwwroot
Start cmd
Exit /B 0
)
:: Запускаем каждый процесс из его рабочей директории
:: MySQL
Call :Log Starting MySQL...
:start-mysql
PushD .\mysql\
Start bin\mysqld --defaults-file="my.ini" --user=root --standalone||Call :Log [ERROR] Can't start MySQL
PopD
If "%1"=="restart" (
Call :Log [WARNING] MySQL crashed, restarting
Exit /B
)
:: PHP
Call :Log Starting PHP-FPM...
:start-php
PushD .\php
:: меняя что-то тут, не забываем изменить в nginx\conf\nginx.conf, секция upstream backend
Start hidcon php-cgi -b 127.0.0.1:9123 -c ".\php.ini"||Call :Log [ERROR] Can't start PHP
::Start hidcon php-cgi -b 127.0.0.1:9124 -c ".\php.ini"||Call :Log [ERROR] Can't start PHP
PopD
If "%1"=="restart" (
Call :Log [WARNING] PHP-FPM crashed, restarting
Exit /B
)
:: nginx
Call :Log Starting NginX...
:start-nginx
PushD .\nginx
Start nginx||Call :Log [ERROR] Can't start NginX
PopD
If "%1"=="restart" (
Call :Log [WARNING] NginX crashed, restarting
Exit /B
)
:: Убиваем уже не нужные процессы hidcon
TaskKill /F /IM "hidcon.exe"
:: Повышаем приоритет для запущенных процессов
For %%A In ("mysqld.exe", "php-cgi.exe", "nginx.exe") Do (
wmic process where name="%%~A" CALL setpriority "high priority"
)
:: Создаём lock-файл и следим за его наличием
Set LockFile=.\.%~n0.lock
Echo.>"%LockFile%"
:Watcher
Ping -n %WatcherTimeout% 127.0.0.1>nul 2>nul
:: Проверяем наличие процессов и перезапускаем в случае падения
TaskList /FI "imagename EQ php-cgi.exe" /FO:CSV|FindStr /I /C:"php-cgi.exe">nul||Call :start-php restart
:: Запускаем процесс выключения, если файл удалён
If Not Exist "%LockFile%" (
Call :Log Lockfile not found, killing child processes
rem Останавливаем nginx
PushD .\nginx
nginx -s stop
PopD
rem Останавливаем MySQL
mysqladmin -u root -p%_DBPASS% shutdown
rem Останавливаем PHP-CGI
rem эта дрянь не поддерживает корректное отключение
rem поэтому просто дергаем TerminateProcess() aka SIGKILL
TaskKill /F /T /IM php-cgi.exe
Call :Log Loader stopped
Exit
)
GoTo :Watcher
:Log
Call Echo %TimestampFormat% %*>>"%LogFile%"
Exit /B
Есть скрипт — загрузчик, который стартует портабельную сборку nginx + php + mysql + доп. модули, он рассчитан на запуск как от юзера, так и в качестве сервиса (например, через nssm). Хотелось бы организовать пул процессов интерпретатора php-cgi на разных портах, и такая возможность в принципе есть через конфиг бэкенда в nginx, но для отслеживания возможных падений (а у php это не столько редко случается) и перезапуска конкретного экземпляра мне нужен PID запущенного процесса. Я знаю о возможности запуска через wmic process call create с получением PID дочернего процесса, но тут есть проблема: я запускаю через hidcon, соответственно получаю PID hidcon-а, а не php-cgi.
Собственно, вопрос: как запустить без видимого окна и получить PID? Или каким ещё образом можно отслеживать одинаковые процессы, запущенные с разными аргументами?
@Echo Off
:: Portable nginx+php+mysql for Windows
:: Inquisitor, 2013-2019
:: nginx 1.17.1
:: php 7.2.19 + composer
:: mysql 5.7.23
CD /D "%~dp0"
:: Лог работы скрипта
Set LogFile=%~dpn0.log
:: Формат даты в логе
Set TimestampFormat=[%%Date%% %%Time:~,8%%]
:: Периодичность проверки запроса на отключение и перезапуска процессов при падении, секунды
Set WatcherTimeout=10
:: Обрабатываем команду на выключение
If /I "%~1"=="shutdown" (
If Exist "%~dp0.loader.lock" (
Call :Log Received termination signal, shutting down
Del "%~dp0.loader.lock" 2>nul
) Else (
Call :Log [WARNING] Received termination signal, server not started
)
Exit /B
)
:: Обрабатываем запуск сервиса
If /I "%~1"=="service" (
Call Echo.>>"%LogFile%"
Call :Log Loader started as service
GoTo :service
)
:: Перезапускаем себя как скрытый процесс, если запущено без аргументов
If "%~1"=="" (
Start "" "%~dp0tools\hidcon" %~nx0 restart_hidden
Call Echo.>>"%LogFile%"
Call :Log Loader started
Exit
)
:service
:: Сохраняем оригинальный path
Set OSPath=%Path%
:: Добавляем пути к бинарникам в системный path для этого скрипта и дочерних процессов
Set Path=%~dp0tools;%~dp0nginx;%~dp0php;%~dp0mysql\bin
:: Добавляем модули
:: FFMpeg 4.1.3
Set Path=%Path%;%~dp0modules\ffmpeg
:: ImageMagick 6.9.3 (php7)
Set Path=%Path%;%~dp0modules\imagick-php7\ImageMagick
Set LOCALAPPDATA=%~dp0modules\imagick-php5
:: Меняем системный temp на наш
Set Temp=%~dp0\tmp
:: Добавляем системный path с низшим приоритетом
Set Path=%Path%;%OSPath%
:: Обрабатываем запуск консоли в рабочем окружении (Composer \ RIOX)
If /I "%~1"=="console" (
PushD nginx\wwwroot
Start cmd
Exit /B 0
)
:: Запускаем каждый процесс из его рабочей директории
:: MySQL
Call :Log Starting MySQL...
:start-mysql
PushD .\mysql\
Start bin\mysqld --defaults-file="my.ini" --user=root --standalone||Call :Log [ERROR] Can't start MySQL
PopD
If "%1"=="restart" (
Call :Log [WARNING] MySQL crashed, restarting
Exit /B
)
:: PHP
Call :Log Starting PHP-FPM...
:start-php
PushD .\php
:: меняя что-то тут, не забываем изменить в nginx\conf\nginx.conf, секция upstream backend
Start hidcon php-cgi -b 127.0.0.1:9123 -c ".\php.ini"||Call :Log [ERROR] Can't start PHP
::Start hidcon php-cgi -b 127.0.0.1:9124 -c ".\php.ini"||Call :Log [ERROR] Can't start PHP
PopD
If "%1"=="restart" (
Call :Log [WARNING] PHP-FPM crashed, restarting
Exit /B
)
:: nginx
Call :Log Starting NginX...
:start-nginx
PushD .\nginx
Start nginx||Call :Log [ERROR] Can't start NginX
PopD
If "%1"=="restart" (
Call :Log [WARNING] NginX crashed, restarting
Exit /B
)
:: Убиваем уже не нужные процессы hidcon
TaskKill /F /IM "hidcon.exe"
:: Повышаем приоритет для запущенных процессов
For %%A In ("mysqld.exe", "php-cgi.exe", "nginx.exe") Do (
wmic process where name="%%~A" CALL setpriority "high priority"
)
:: Создаём lock-файл и следим за его наличием
Set LockFile=.\.%~n0.lock
Echo.>"%LockFile%"
:Watcher
Ping -n %WatcherTimeout% 127.0.0.1>nul 2>nul
:: Проверяем наличие процессов и перезапускаем в случае падения
TaskList /FI "imagename EQ php-cgi.exe" /FO:CSV|FindStr /I /C:"php-cgi.exe">nul||Call :start-php restart
:: Запускаем процесс выключения, если файл удалён
If Not Exist "%LockFile%" (
Call :Log Lockfile not found, killing child processes
rem Останавливаем nginx
PushD .\nginx
nginx -s stop
PopD
rem Останавливаем MySQL
mysqladmin -u root -p%_DBPASS% shutdown
rem Останавливаем PHP-CGI
rem эта дрянь не поддерживает корректное отключение
rem поэтому просто дергаем TerminateProcess() aka SIGKILL
TaskKill /F /T /IM php-cgi.exe
Call :Log Loader stopped
Exit
)
GoTo :Watcher
:Log
Call Echo %TimestampFormat% %*>>"%LogFile%"
Exit /B