Skip to content

Symfony Scheduler integration proposal #200

@mleczakm

Description

@mleczakm

Having ability to run cron tasks using symfony scheduler would be really useful, I don't know currently how should it be handled: using tick, another sub-process or on task handling.
I will try with rewriting Symfony\Component\Scheduler class to make it non-blocking, so I will remove while loop and sleep and run it using tick inside custom configurator, WithScheduler implementing SwooleBundle\SwooleBundle\Server\Configurator.

It is possible, only custom scheduler must be written, something like:

class Scheduler
{
    /**
     * @var array<MessageGenerator>
     */
    private array $generators = [];
    private int $index = 0;
    /**
     * @param iterable<ScheduleProviderInterface> $scheduleProviders
     */
    public function __construct(private MessageBusInterface $bus, array $scheduleProviders, private readonly ClockInterface $clock = new Clock(), private readonly ?EventDispatcherInterface $dispatcher = null)
    {

        foreach ($scheduleProviders as $scheduleProvider) {
            $this->addSchedule($scheduleProvider->getSchedule());
        }
    }

    public function addSchedule(Schedule $schedule): void
    {
        $this->addMessageGenerator(new MessageGenerator($schedule, 'schedule_' . $this->index++, $this->clock));
    }

    public function addMessageGenerator(MessageGenerator $generator): void
    {
        $this->generators[] = $generator;
    }
    public function run(): void
    {

        foreach ($this->generators as $generator) {
            foreach ($generator->getMessages() as $context => $message) {
                if (!$this->dispatcher) {
                    $this->bus->dispatch($message);

                    continue;
                }

                $preRunEvent = new PreRunEvent($generator->getSchedule(), $context, $message);
                $this->dispatcher->dispatch($preRunEvent);

                if ($preRunEvent->shouldCancel()) {
                    continue;
                }

                try {
                    $this->bus->dispatch($message);

                    $this->dispatcher->dispatch(new PostRunEvent($generator->getSchedule(), $context, $message));
                } catch (Throwable $error) {
                    $failureEvent = new FailureEvent($generator->getSchedule(), $context, $message, $error);
                    $this->dispatcher->dispatch($failureEvent);

                    if (!$failureEvent->shouldIgnore()) {
                        throw $error;
                    }
                }
            }
        }
    }
}

then configured with

        \Swoole\Timer::tick(1000, function () {
            $this->scheduler->run();
        });

and as a result, you are able to provide schedules with any frequency:

        return (new Schedule())
            ->stateful($this->cache)
            ->with(
                RecurringMessage::every(
                    3,
                    new DummyCommand()
                )
            )
            ;

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions