Skip to content

#220 - Throw a ProcessFailedException instead of a FatalError on the stop error strategy - #224

Merged
njoubert-cleverage merged 1 commit into
mainfrom
220
Sep 28, 2026
Merged

njoubert-cleverage merged 1 commit into
mainfrom
220

Conversation

@njoubert-cleverage

Copy link
Copy Markdown
Member

Description

Fixes #220.

When a task fails with the stop error strategy (the default), the process manager throws a Symfony\Component\ErrorHandler\Error\FatalError. This has three consequences:

  • The command exits with code 0 when a process fails: FatalError is an \Error, not an \Exception, and the console application does not turn it into a non-zero exit code. A cron job, a CI job or a supervisor cannot detect failures. An unknown process code, which throws an \Exception, exits with code 1.
  • ProcessLauncherTask does not detect failed sub-processes: it relies on the sub-process exit code, so a sub-process failing in stop strategy is considered successful and the parent process ends with "executed successfully".
  • The original exception is lost: only its message (and file/line) is copied, it is not attached as previous. Its class, code and trace are lost, and a catch (\Exception) around ProcessManager::execute() does not catch the failure.

This PR:

  • Add a dedicated CleverAge\ProcessBundle\Exception\ProcessFailedException (a \RuntimeException implementing ProcessExceptionInterface), thrown instead of the FatalError, with the same message and the original exception as previous.
  • As a consequence, the command exits with code 1 on failure, and ProcessLauncherTask detects failed sub-processes.
  • Update the documentation (01-quick_start.md automation section, 04-advanced_workflow.md, 06-testing.md), add tests.

The new regression tests fail on main and pass with this fix. PHPUnit, PHPStan, PHP-CS-Fixer and Rector pass.

Requirements

  • Documentation updates
    • Reference
    • Cookbooks
    • Changelog
  • Unit tests

Breaking changes

Minor: the exception thrown on a stop failure is now a ProcessFailedException (\RuntimeException) instead of a FatalError (\Error). Code catching FatalError or \Error explicitly must catch ProcessFailedException instead (catch (\Throwable) keeps working). Scripts relying on the (wrong) exit code 0 of a failed process now get 1. symfony/error-handler is no longer used by src/ but is kept in composer.json.

🤖 Generated with Claude Code

…Exception` (with the original exception as `previous`) instead of a `FatalError`, so that the command exits with a non-zero code when a process fails and `ProcessLauncherTask` detects failed sub-processes. Update documentation, add tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@njoubert-cleverage
njoubert-cleverage merged commit 3d1a9ff into main Sep 28, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A process failing with the stop error strategy throws a FatalError: exit code 0, original exception lost, failed sub-processes not detected

1 participant