eliashaeussler / task-runner
Progress helper for long-running CLI tasks, based on Symfony Console
Installs: 165
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 1
pkg:composer/eliashaeussler/task-runner
Requires
- php: ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0
- symfony/console: ^5.4 || ^6.0 || ^7.0 || ^8.0
Requires (Dev)
- armin/editorconfig-cli: ^2.2
- eliashaeussler/php-cs-fixer-config: ^3.1
- eliashaeussler/phpstan-config: ^4.0
- eliashaeussler/rector-config: ^4.0
- ergebnis/composer-normalize: ^2.48
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-phpunit: ^2.0
- phpunit/phpunit: ^11.5 || ^12.5
- shipmonk/composer-dependency-analyser: ^1.8
This package is auto-updated.
Last update: 2025-12-26 20:41:04 UTC
README
Task Runner
Task Runner is a simple PHP library targeted for CLI-oriented applications and projects. It provides a progress helper for long-running CLI tasks, based on Symfony Console.
🔥 Installation
composer require eliashaeussler/task-runner
⚡️ Usage
Basic usage
A common use case is to wrap a long-running process in a
TaskRunner instance, which handles progress
messages and the overall task execution:
use EliasHaeussler\TaskRunner; use Symfony\Component\Console; // 1. Create a new TaskRunner instance $output = new Console\Output\ConsoleOutput(); $taskRunner = new TaskRunner\TaskRunner($output); // 2. Run the task $taskRunner->run( 'Downloading some large files from the internet', static function () { // Do some long-running work here... }, );
This will output the following progress message:
Downloading some large files from the internet... Done
Progress message decorators
User-oriented progress messages are decorated by a
ProgressDecorator instance. By
default, a simple progress decorator is used. It displays the various steps
like follows:
- Progress start:
Downloading some large files from the internet... - Task successful:
Downloading some large files from the internet... Done - Task failed:
Downloading some large files from the internet... Failed
It is possible to pass a customized progress decorator to the TaskRunner
instance:
use EliasHaeussler\TaskRunner; use Symfony\Component\Console; // 1. Create a custom progress decorator $decorator = new class implements TaskRunner\Decorator\ProgressDecorator { public function progress(string $message, bool &$newLine = false): string { return '⏳ '.$message.'... '; } public function done(mixed $result = null): string { return '🥳' } public function failed(?Throwable $exception = null): string { return '💥'; } } // 2. Create a new TaskRunner instance $output = new Console\Output\ConsoleOutput(); $taskRunner = new TaskRunner\TaskRunner($output, $decorator); // 3. Run the task $taskRunner->run( 'Downloading some large files from the internet', static function () { // Do some long-running work here... }, );
The above example will output the following progress messages:
- Progress start:
⏳ Downloading some large files from the internet... - Task successful:
⏳ Downloading some large files from the internet... 🥳 - Task failed:
⏳ Downloading some large files from the internet... 💥
Custom output
Some long-running tasks may also produce output that should be displayed
to the user. For this usecase, the executing task receives a RunnerContext
instance, which holds a buffered output stream. This can be used to write
output to the console:
use EliasHaeussler\TaskRunner; $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context) { // Do some long-running work here... $context->output->writeln('This content is displayed to the user.'); }, );
The additional output will be displayed after the progress message:
Downloading some large files from the internet... Done
This content is displayed to the user.
Error Handling
If an error occurs during the execution of the task, the TaskRunner will
automatically catch it, mark the test execution as failed, and by default
throw the catched exception afterwards:
Downloading some large files from the internet... Failed
PHP Fatal error: Uncaught RuntimeException: Downloading failed.
This behavior can be customized in various ways.
Avoid throwing an exception
In some cases, a thrown exception may not be relevant for the user and hence
should not avoid further execution of the application. This behavior can be
controlled with the passed RunnerContext instance:
use EliasHaeussler\TaskRunner; $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context) { $context->throwExceptions = false; // Do some long-running work here... if ($downloadFailed) { throw new RuntimeException('Downloading failed.'); } }, );
In the above example, the task execution is still marked as failed, but the exception is not thrown afterwards:
Downloading some large files from the internet... Failed
Control task result
In addition, it is also possible to control the task result manually, even if no exception was thrown:
use EliasHaeussler\TaskRunner; $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context) { // Do some long-running work here... if ($downloadFailed) { $context->markAsFailed(); } }, );
In the above example, the task execution is now manually marked as failed:
Downloading some large files from the internet... Failed
Receive task result
If the provided task is successful, the TaskRunner returns the result of
the executed task:
use EliasHaeussler\TaskRunner; $files = $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context) { // Do some long-running work here... return $files; }, ); // $files is now the result of the task
If a task does not provide a result, null will be returned instead:
use EliasHaeussler\TaskRunner; $files = $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context) { // Do some long-running work here... }, ); // $files is always NULL
This, however, can be slightly adapted, if the task is declared as returning
void. In this case, the TaskRunner will return a dedicated
TaskResult object instead:
use EliasHaeussler\TaskRunner; $result = $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context): void { // Do some long-running work here... }, ); // $result is now a TaskResult instance, e.g. TaskResult::Success
In case a task throws an exception and the passed RunnerContext was modified
to avoid throwing exceptions, the TaskResult will return TaskResult::Failed
instead:
use EliasHaeussler\TaskRunner; $result = $taskRunner->run( 'Downloading some large files from the internet', static function (TaskRunner\RunnerContext $context) { $context->throwExceptions = false; // Do some long-running work here... if ($downloadFailed) { $context->markAsFailed(); } }, ); // $result is now a TaskResult::Failed instance
🧑💻 Contributing
Please have a look at CONTRIBUTING.md.
⭐ License
This project is licensed under GNU General Public License 3.0 (or later).