fix(process): accept null pid in ProcessManager checks (CLI monitor crash)

The cs-fix auto-typing narrowed the pid parameters of the /proc-based
process checks to a non-nullable `int` (read from the `@param int $pid`
docblocks). But every one of these methods was written to tolerate a
missing pid: each opens with `$pid = (int) $pid;` and a `$pid <= 0`
guard, and their callers routinely pass nullable DB columns
(`tv_archive_pid`, `monitor_pid`, `vframes_pid`, `streams.pid`, …) and
runtime PIDs that can be null. In production this crashed the monitor
cron:

  ProcessManager::isNamedProcessRunning(): Argument #1 ($pid) must be of
  type int, null given, called in Cli/Commands/MonitorCommand.php:322

Make the pid parameter nullable (`?int`) on the eight affected public
checks — isRunning, isNamedProcessRunning, isStreamRunning,
producerKind, resourceSample, kill, getProcessAge, isStreamAlive,
isMonitorAlive — so the existing `(int) null === 0` cast and guard
return the safe "not running" result instead of a fatal TypeError. The
docblocks are corrected to `int|null` as well so a future cs-fix run
does not re-narrow the types. procExists stays `int` (internal, only
reached after the guard). No behaviour change for valid pids.
This commit is contained in:
Divarion_D
2026-09-13 19:57:38 +03:00
parent e5798ae951
commit cb4d12d99b
+19 -19
View File
@@ -50,11 +50,11 @@ class ProcessManager {
/**
* Check if a process is running via /proc filesystem
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @param string|null $exe Expected executable name (e.g., 'ffmpeg', 'php')
* @return bool
*/
public static function isRunning(int $pid, ?string $exe = null) {
public static function isRunning(?int $pid, ?string $exe = null) {
$pid = (int) $pid;
if ($pid <= 0) {
@@ -85,13 +85,13 @@ class ProcessManager {
*
* Reads /proc/PID/cmdline and matches against "NAME[ID]" pattern.
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @param string $processName Process name prefix (e.g., 'XC_VM', 'Thumbnail', 'TVArchive')
* @param int|string $identifier Stream/task ID
* @param string $exe Expected executable (default: PHP_BIN)
* @param string|null $exe Expected executable (default: PHP_BIN)
* @return bool
*/
public static function isNamedProcessRunning(int $pid, string $processName, int|string $identifier, string $exe = null) {
public static function isNamedProcessRunning(?int $pid, string $processName, int|string $identifier, ?string $exe = null) {
$pid = (int) $pid;
if ($pid <= 0) {
@@ -131,11 +131,11 @@ class ProcessManager {
* Specialized check for streaming processes that match
* either ffmpeg with specific stream output files, or PHP processes.
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @param int $streamId Stream ID
* @return bool
*/
public static function isStreamRunning(int $pid, int $streamId) {
public static function isStreamRunning(?int $pid, int $streamId) {
$pid = (int) $pid;
if ($pid <= 0) {
@@ -173,11 +173,11 @@ class ProcessManager {
/**
* What kind of producer a stream's pid is, for the panel's stream list.
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @return string|null 'fanout' (xc_fanout remux), 'ffmpeg', 'php' (the LLOD
* segmenter / loopback relay), or null when it cannot be read.
*/
public static function producerKind(int $pid) {
public static function producerKind(?int $pid) {
$pid = (int) $pid;
if ($pid <= 0 || !self::procExists($pid) || !is_readable('/proc/' . $pid . '/exe')) {
@@ -208,10 +208,10 @@ class ProcessManager {
* size in bytes, which is the figure that matters for a box running hundreds
* of encoders: what they actually hold in RAM.
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @return array{ticks:int,rss:int,at:float,start:int}|null Null when the process is gone.
*/
public static function resourceSample(int $pid) {
public static function resourceSample(?int $pid) {
$pid = (int) $pid;
if ($pid <= 1) {
@@ -339,11 +339,11 @@ class ProcessManager {
/**
* Kill a process by PID
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @param int $signal Signal to send (default: SIGKILL = 9)
* @return bool
*/
public static function kill(int $pid, int $signal = 9) {
public static function kill(?int $pid, int $signal = 9) {
$pid = (int) $pid;
if ($pid <= 0) {
@@ -369,10 +369,10 @@ class ProcessManager {
* watchdog blocked in poll() on a half-open MariaDB socket): a normally
* short-lived generation that has been alive far too long is stale.
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @return int Age in seconds, or -1 if it cannot be determined
*/
public static function getProcessAge(int $pid) {
public static function getProcessAge(?int $pid) {
$pid = (int) $pid;
if ($pid <= 0 || !self::procExists($pid)) {
@@ -506,11 +506,11 @@ class ProcessManager {
* Extracted from ProcessManager::isStreamAlive().
* Searches for $streamID anywhere in /proc/PID/cmdline (case-insensitive).
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @param int|string $streamID Stream identifier to search for
* @return bool
*/
public static function isStreamAlive(int $pid, int|string $streamID) {
public static function isStreamAlive(?int $pid, int|string $streamID) {
$pid = (int) $pid;
if ($pid <= 1) {
return false;
@@ -548,12 +548,12 @@ class ProcessManager {
* Extracted from ProcessManager::isMonitorAlive().
* Checks for XC_VM[streamID] OR XC_VMProxy[streamID] in cmdline.
*
* @param int $pid Process ID
* @param int|null $pid Process ID (null/0 -> not running)
* @param int|string $streamID Stream identifier
* @param string|null $exe Expected executable (default: PHP_BIN)
* @return bool
*/
public static function isMonitorAlive(int $pid, int|string $streamID, ?string $exe = null) {
public static function isMonitorAlive(?int $pid, int|string $streamID, ?string $exe = null) {
$pid = (int) $pid;
if ($pid <= 0) {
return false;