Skip to content

Commit

Permalink
Added ReactPHP EventLoop and standalone cron runner engine.
Browse files Browse the repository at this point in the history
  • Loading branch information
vtsykun committed Aug 19, 2023
1 parent cc9e758 commit 369b96b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 9 deletions.
70 changes: 69 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ To use this option need to install symfony [lock component](https://symfony.com/
- `arguments` - Array of arguments, used to run symfony console commands or pass arguments to handler.
- `priority` - Sorting priority.
- `group` - Group name, see Cron Grouping section.
- `jitter` - Random delay 0-60 sec
- `interval` - Run periodic tasks by interval. Examples `10`, `10 seconds`, `1 day`.
- `messenger` - Send jobs into Messenger Bus. Default `false`. You also can specify transport here `{routing: async}`,
see [Symfony Routing Messages to a Transport](https://symfony.com/doc/current/messenger.html#routing-messages-to-a-transport)

Expand Down Expand Up @@ -453,10 +455,76 @@ See example of customization
## Use ReactPHP EventLoop

You can add your own periodic tasks directly to `Loop`.
The bundle uses a simple wrapper `Okvpn\Bundle\CronBundle\Runner\ScheduleLoopInterface` for the library
The bundle uses a simple wrapper `Okvpn\Bundle\CronBundle\Runner\ScheduleLoopInterface` for the library `react/event-loop`

```php
<?php
use Okvpn\Bundle\CronBundle\Event\LoopEvent;
use Okvpn\Bundle\CronBundle\Runner\TimerStorage;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

class CronStartListener
{
#[AsEventListener('loopInit')]
public function loopInit(LoopEvent $event): void
{
$dataDogS = $this->getDDog();
$event->getLoop()->addPeriodicTimer(6.0, static function () use ($dataDogS) {
$dataDogS->set('crond', getmypid());
});
}
}
```

#### Configure ReactPHP adapter

Need to install [react/event-loop](https://github.com/reactphp/event-loop) if you want to use with async I/O, for example for handle websockets, redis.

```
composer req react/event-loop
```

```yaml
# Add file to config/packages/*
okvpn_cron:
loop_engine: okvpn_cron.react_loop # service name
```
```php
<?php
use Okvpn\Bundle\CronBundle\Event\LoopEvent;
use Okvpn\Bundle\CronBundle\Runner\TimerStorage;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Okvpn\Bundle\CronBundle\Runner\TimerStorage;
use React\EventLoop\Loop;

class CronStartListener
{
public function __construct(
private TimerStorage $timers,
) {
}

#[AsEventListener('loopInit')]
public function loopInit(LoopEvent $event): void
{
$redis = new RedisClient('127.0.0.1:6379');
$timers = $this->timers;
$loop = $event->getLoop();

$redis->on('message', static function (string $channel, string $payload) use ($timers, $loop) {
[$command, $args] = unserialize($payload);
if ($timers->hasTimer($envelope = $timers->find($command, $args))) {
[$timer] = $timers->getTimer($envelope);
$loop->futureTick($timer);
}
});

Loop::addPeriodicTimer(5.0, static function () use ($redis) {
$redis->ping();
});
}
}
```

License
Expand Down
8 changes: 1 addition & 7 deletions src/Command/CronCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,12 @@ protected function executeLoop(InputInterface $input, OutputInterface $output):
});
}

$test = 0;
$schedulerRunner = function () use ($input, $output, $loop, &$test) {
$schedulerRunner = function () use ($input, $output, $loop) {
$runAt = \microtime(true);
if ($loop instanceof ReactLoopAdapter) {
$loop->setDefaultLoopTime($this->getCurrentDate());
}

if ($runAt - $test < 2) {
$output->writeln("ERROR");
}
$test = $runAt;

$this->scheduler($input, $output);
$output->writeln(sprintf('[%s] All schedule tasks completed in %.3f seconds', $this->getCurrentDate()->format('Y-m-d H:i:s.u'), \microtime(true) - $runAt), OutputInterface::VERBOSITY_VERBOSE);
if ($loop instanceof ReactLoopAdapter) {
Expand Down
1 change: 1 addition & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->integerNode('timeout')->end()
->scalarNode('interval')->end()
->integerNode('jitter')->end()
->end()
->end()
->end();
Expand Down
1 change: 0 additions & 1 deletion src/Runner/StandaloneLoop.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ public function cancelTimer($timer): void
}
}

$this->timers = \array_values($this->timers);
$this->needSort = true;
}

Expand Down

0 comments on commit 369b96b

Please sign in to comment.