m6web / daemon-bundle
bundle sf easing creating daemon commands
Installs: 289 281
Dependents: 0
Suggesters: 0
Security: 0
Stars: 59
Watchers: 47
Forks: 12
Open Issues: 0
Type:symfony-bundle
Requires
- php: >=8.1
- ext-pcntl: *
- psr/event-dispatcher: >=1.0
- react/event-loop: @stable
- symfony/console: ~6.1||~7.0
- symfony/framework-bundle: ~6.1||~7.0
- symfony/yaml: ~6.1||~7.0
Requires (Dev)
- phpunit/phpunit: ^8.4
README
Table of Contents
DaemonBundle
Allows you to create daemonized commands with the React event-loop component.
Installation
Via composer :
composer require m6web/daemon-bundle
Note:
- If you are using a symfony version
>= 4.3
use the lastest version - For symfony versions between
2.3
and3.0
, you can usem6web/daemon-bundle:^1.4
- For PHP versions
>=5.5.9
and<7.0
support, you can usem6web/daemon-bundle:^3.0
For more information about installation of plugin refers the documentation of symfony for your version.
Configuration
You can optionally define events which are triggered each X iterations:
m6_web_daemon: iterations_events: - count: 10 name: Path\From\Your\Project\Event\EachTenEvent - count: 5 name: Path\From\Your\Project\Event\EachFiveEvent
Your event need to extends the AbstractDaemonEvent like following:
<?php namespace Path\From\Your\Project\Event; use M6Web\Bundle\DaemonBundle\Event\AbstractDaemonEvent; class EachFiveEvent extends AbstractDaemonEvent { }
This bundle use the PSR-14 implementation for event dispatcher so you need to register the symfony event dispatcher in your config/services.yaml
like this:
# config/services.yaml services: # ... others declarations Psr\EventDispatcher\EventDispatcherInterface: "@event_dispatcher"
Usage
This command uses the event-loop component which ReactPHP is used to run loops and other asynchronous tasks.
<?php namespace App\Command; use M6Web\Bundle\DaemonBundle\Command\DaemonCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class DaemonizedCommand extends DaemonCommand { protected function configure() { $this ->setName('daemonized:command') ->setDescription('My daemonized command'); } protected function setup(InputInterface $input, OutputInterface $output): void { // Set up your daemon here // Add your own optional callback : called every 10 iterations $this->addIterationsIntervalCallback(10, [$this, 'executeEveryTenLoops']); // You can add your own Periodic Timer, // Here this timer will be called every 0.5s $daemon = $this; $this->loop->addPeriodicTimer(0.5, function ($timer) use ($daemon) { // It's the last loop, cancel the timer. if ($daemon->isLastLoop()) { $daemon->loop->cancelTimer($timer); } }); } /** * Execute is called at every loop */ protected function execute(InputInterface $input, OutputInterface $output) { $output->writeln("Iteration"); // This method helps to give back the CPU to the react-loop. // So you can wait between two iterations if your workers has nothing to do. $this->setNextIterationSleepingTime(1000000); // Every second } /** * executeEveryTenLoops is called every 10 loops */ protected function executeEveryTenLoops(InputInterface $input, OutputInterface $output): void { $output->writeln("Iteration " . $this->getLoopCount()); } }
You also need to declare your command under the services:
# config/services services: # ... others declarations App\Command\DaemonizedCommand: parent: M6Web\Bundle\DaemonBundle\Command\DaemonCommand tags: - console.command
For information, you need to declare the autowire
and autoconfigure
parameters (to false
) only if you have defaults parameters for services (under _default
)
Run command
You can run a daemonized command as any other Symfony command with bin/console
. DaemonCommand parent class provide additional options :
--run-once
- Run the command just once--run-max
- Run the command x time--memory-max
- Gracefully stop running command when given memory volume, in bytes, is reached--shutdown-on-exception
- Ask for shutdown if an exception is thrown--show-exceptions
- Display exceptions on command output stream
Command events
Daemonized command trigger the following events :
DaemonEvents::DAEMON_START
DaemonEvents::DAEMON_LOOP_BEGIN
DaemonEvents::DAEMON_LOOP_EXCEPTION_STOP
DaemonEvents::DAEMON_LOOP_EXCEPTION_GENERAL
DaemonEvents::DAEMON_LOOP_MAX_MEMORY_REACHED
DaemonEvents::DAEMON_LOOP_ITERATION
DaemonEvents::DAEMON_LOOP_END
DaemonEvents::DAEMON_STOP