From 5e6469e2b649ee2fdf5d1a4234e3dce5b49eb9c7 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Sun, 5 Jul 2026 10:33:39 +0200 Subject: [PATCH 1/2] fix(jobs): resolve portability issues with background job cleanup The previous implementation executes "ps" with flags -p and -o to check whether a job process was still running. This approach has portability issues regarding e.g. BusyBox ps (Alpine Linux) where `ps -p` fails or BSD/macOS where `ps -o` fails. Replace with `posix_kill($pid, 0)`, the standard POSIX way to probe process existence without delivering a signal. EPERM is treated as "process exists but not owned by current user". This should be available on all supported platforms. Fixes: 60ce92a697dd357465db65f11e10c85cc5404d70 Suggested-by: Michele Marcionelli Signed-off-by: Stefan Kalscheuer --- core/BackgroundJobs/CleanupBackgroundJobsJob.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/core/BackgroundJobs/CleanupBackgroundJobsJob.php b/core/BackgroundJobs/CleanupBackgroundJobsJob.php index 6242941eed1ba..b4aa9d79e5efa 100644 --- a/core/BackgroundJobs/CleanupBackgroundJobsJob.php +++ b/core/BackgroundJobs/CleanupBackgroundJobsJob.php @@ -47,11 +47,9 @@ private function reapCrashedJobs(): void { if ($job->serverId !== $currentServerId) { continue; } - $output = []; - $result = 0; - exec('ps -p ' . escapeshellarg((string)$job->pid) . ' -o cmd', $output, $result); - if (count($output) === 1 && current($output) === 'CMD' && $result === 1) { - // Process doesn't exists anymore + $processExists = posix_kill($job->pid, 0) || posix_get_last_error() === 1 /* EPERM */; + if (!$processExists) { + // Process doesn't exist anymore $maxDuration = (new DateTimeImmutable())->diff($job->startedAt); $maxDuration = ($maxDuration->days * 24 * 60 * 60 * 1000) From 254b39ef9b30c927e2100cfed174d6a4e62a15b2 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Sun, 5 Jul 2026 10:50:13 +0200 Subject: [PATCH 2/2] fix(jobs): restore background_jobs_expiration_days behavior Snowflake ID in `JobRuns:deleteBefore()` is computed from given timestamp, but immediately overwritten by a literal value making the expiration setting have no effect. This looks like a leftover artifact from development that should be cleaned up. Remove the hardcoded ID to restore the desired behavior. Fixes: dc5499af4699d6adfbd30f60bc2df26012f8d39d Suggested-by: Michele Marcionelli Signed-off-by: Stefan Kalscheuer --- lib/private/BackgroundJob/JobRuns.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/private/BackgroundJob/JobRuns.php b/lib/private/BackgroundJob/JobRuns.php index 51145a9c1947c..8ff7a016271c4 100644 --- a/lib/private/BackgroundJob/JobRuns.php +++ b/lib/private/BackgroundJob/JobRuns.php @@ -63,7 +63,6 @@ public function finished(int|string $runId, int $duration, int $memoryPeakUsage, public function deleteBefore(int $timestamp): int { $beforeSnowflake = $this->snowflakeGenerator->minForTimeId($timestamp); - $beforeSnowflake = '91480652934574081'; $qb = $this->connection->getQueryBuilder(); $result = $qb ->delete(self::TABLE)