CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Ответить
Аватара пользователя
Guest

CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Сообщение Guest »

Приветствую уважаемых форумчан.

Есть скрипт — загрузчик, который стартует портабельную сборку nginx + php + mysql + доп. модули, он рассчитан на запуск как от юзера, так и в качестве сервиса (например, через nssm). Хотелось бы организовать пул процессов интерпретатора php-cgi на разных портах, и такая возможность в принципе есть через конфиг бэкенда в nginx, но для отслеживания возможных падений (а у php это не столько редко случается) и перезапуска конкретного экземпляра мне нужен PID запущенного процесса. Я знаю о возможности запуска через wmic process call create с получением PID дочернего процесса, но тут есть проблема: я запускаю через hidcon, соответственно получаю PID hidcon-а, а не php-cgi.

Собственно, вопрос: как запустить без видимого окна и получить PID? Или каким ещё образом можно отслеживать одинаковые процессы, запущенные с разными аргументами?



Скрипт в текущем виде

[spoiler]Код:
[/spoiler]

Код: Выделить всё

@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
Аватара пользователя
Iska

Re: CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Сообщение Iska »

Цитата Anonymоus:



я запускаю через hidcon,
CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса




А Вы не запускайте через hidecon.exe. Вам для чего hidecon.exe? Для того, чтобы скрыть консоль от пакетного файла. А Вы используйте не пакетный файл, а WSH.




Цитата Anonymоus:





Код:

Код: Выделить всё

CD /D "%~dp0"

CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса




…может сыграть с Вами очень злую шутку при попытке исполнения данного пакетного файла с разделённого ресурса.
Аватара пользователя
Guest

Re: CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Сообщение Guest »

Цитата Iska:



А Вы используйте не пакетный файл, а WSH
CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса




Да, похоже это единственный вменяемый вариант (кроме написания самостоятельно аналога hidcon, который будет возвращать PID)

Тогда попрошу подсказки, как в VBS вернуть PID процесса в stdout или errorlevel, чтобы получить его основным скриптом.
Аватара пользователя
Guest

Re: CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Сообщение Guest »

WSH оказался не лучшим вариантом, в тестовой сборке у пользователей пошли ложно-положительные срабатывания антивирусов именно на сам vbs, а обьяснять каждому, как в этом зоопарке антивирусов добавить в исключения, мне честно говоря лень.

Пришлось идти по сложному варианту и просить друга помочь с написанием аналога hidcon. Выкладываю здесь, вдруг кому ещё пригодится, исходники в том же архиве, C++, собрано под x86.



Синтаксис: easy_spawner "" ...

Вызываемая программа может как находиться в PATH, так и быть указана полным или относительным путем. Второй и последующий аргументы передаются вызываемой программе.

PID запущенного процесса выводится в stdout и легко получается конструкцией вида

Код:

Код: Выделить всё

For /F "delims=" %%P In ('easy_spawner' "program.exe" -arg1=test --test') Do Set PID=%%~P

Если вызываемая программа не смогла запуститься, easy_spawner устанавливает errorlevel в 1 и выводит сообщение об ошибке от программы.
Вложения
easy_spawner.zip
(14.15 КБ) 0 скачиваний
easy_spawner.zip
(14.15 КБ) 0 скачиваний
Аватара пользователя
Patroklos

Re: CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Сообщение Patroklos »

А на какой ОС вы используете easy_spawner?

А то у меня на 10 х64 не фурычит.

Какие-то окошки мигают но в таскменеджере видно что ничего не запущенно.
Аватара пользователя
Patroklos

Re: CMD/BAT - [решено] Запуск без видимого окна с получением PID дочернего процесса

Сообщение Patroklos »

Patroklos, тестировалось на x64 Win10 Enterprise, тестовые сборки проверял на x86 Win10 Home. Имейте в виду, у файла нету цифровой подписи, поэтому при первом запуске его может блокировать SmartScreen.

Попробуйте добавить в path ту директорию, из которой запускаете целевой exe. Вот живой пример того, как используется у меня:

HTML код:

Код: Выделить всё

Set PHP_Pool[]="9123","9124","9125"
For %%A In (%PHP_Pool[]%) Do (
	For /F "delims=" %%P In ('easy_spawner "php-cgi.exe" "-b 127.0.0.1:%%~A -c .\php.ini"') Do (
		Call :Log New PHP worker on port :%%~A with PID %%P
		Set _PHP_%%~A=%%P
	)
)
Ответить

Вернуться в «Скриптовые языки администрирования Windows»