diff --git a/src/Worker/SchedulerWorker.php b/src/Worker/SchedulerWorker.php index 1a369d2..f33071a 100644 --- a/src/Worker/SchedulerWorker.php +++ b/src/Worker/SchedulerWorker.php @@ -152,7 +152,17 @@ private function runCallback(TriggerInterface $trigger, string $service, string $childExitCode = 0; try { ($this->handler)($service, $taskName); - } catch (\Throwable) { + } catch (\Throwable $e) { + $this->worker->log(sprintf( + '%s Task "%s" failed: [%s] %s in %s:%d\nStack trace:\n%s', + $this->worker->name, + $taskName, + $e::class, + $e->getMessage(), + $e->getFile(), + $e->getLine(), + $e->getTraceAsString(), + )); $childExitCode = 1; } finally { // Release lock, cleanup and exit diff --git a/tests/SchedulerWorkerSigchldTest.php b/tests/SchedulerWorkerSigchldTest.php index 3beb0b9..47f3fe6 100644 --- a/tests/SchedulerWorkerSigchldTest.php +++ b/tests/SchedulerWorkerSigchldTest.php @@ -87,6 +87,49 @@ public function testSchedulerWorkerUsesCorrectSignalPattern(): void ); } + /** + * Structural test: verify SchedulerWorker logs exceptions in child process. + * This is a regression safety net for Issue #157 — if someone removes the + * exception logging or reverts to silently swallowing exceptions, this test + * catches it immediately. + */ + public function testSchedulerWorkerLogsExceptionsInChildProcess(): void + { + $sourceFile = dirname(__DIR__) . '/src/Worker/SchedulerWorker.php'; + $this->assertFileExists($sourceFile); + + $content = file_get_contents($sourceFile); + $this->assertNotFalse($content); + + // Verify the catch block captures the exception variable + $this->assertStringContainsString( + 'catch (\Throwable $e)', + $content, + 'Catch block must capture exception variable for logging (Issue #157)', + ); + + // Verify the exception is logged via Worker::log() + $this->assertStringContainsString( + '$this->worker->log(sprintf(', + $content, + 'Exception must be logged via Worker::log() in child process (Issue #157)', + ); + + // Verify the log message includes exception type + $this->assertStringContainsString( + '$e::class', + $content, + 'Log message must include exception type for quick identification (Issue #157)', + ); + + // Verify the log message includes stack trace + $this->assertStringContainsString( + '$e->getTraceAsString()', + $content, + 'Log message must include stack trace for full diagnostic information (Issue #157)', + ); + } + /** * Run a SIGCHLD test in an isolated PHP process to avoid PHPUnit * state inheritance issues with pcntl_fork().