Upgrade to Pro — share decks privately, control downloads, hide ads and more …

AFUP Bordeaux - Discover the symfony scheduler ...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

AFUP Bordeaux - Discover the symfony scheduler component

Avatar for Kélian Bousquet

Kélian Bousquet

May 22, 2024

More Decks by Kélian Bousquet

Other Decks in Programming

Transcript

  1. History [Scheduler][Component] Scheduler #35315 - 12/01/2020 - @Guikingone (Guillaume Loulier)

    [Messenger] Add a scheduler component #47112 - 29/07/2020 - @upyx (Sergey Rabochiy) First released on March 2023 | 645,239 downloads (4,947 per day) No longer experimental as of Symfony 6.4
  2. Introduction The scheduler component manages task scheduling within your PHP

    application, like running a task each night at 3 AM, every two weeks except for holidays or any other custom schedule you might need. This component is useful to: Database cleanup Cache clearing Data synchronization Emails Alerts From Symfony Scheduler documentation
  3. Installation $ composer require symfony/scheduler OR $ composer require scheduler

    The Scheduler component requires the Messenger component to work!
  4. Installation $ composer require symfony/scheduler OR $ composer require scheduler

    The Scheduler component requires the Messenger component to work!
  5. How to run $ bin/console messenger:consume scheduler_default [OK] Consuming messages

    from transport "scheduler_default". // The worker will automatically exit once it has received a stop signal via // the messenger:stop-workers command. // Quit the worker with CONTROL-C. // Re-run the command with a -vv option to see logs about consumed messages.
  6. How to use Easy level // src/Command/ClockCommand.php #[ AsCommand (

    name : 'app:clock')] #[ AsPeriodicTask ( frequency : '1 minute', from : '2024-05-22', until : '2024-12-31')] // #[AsCronTask('* * * * *')] (require dragonmantank/cron-expression) final class ClockCommand extends Command { public function __construct( #[ Autowire ( env : 'CLOCK_MUSIC')] private readonly string $clockMusic ) { parent::__construct(); } protected function execute( InputInterface $input, OutputInterface $output): int { $command = sprintf('mplayer %s', $this ->clockMusic); shell_exec($command); } } return Command ::SUCCESS;
  7. How to use Intermediate level (1/2) // src/Message/PlayMusicMessage.php final readonly

    class PlayMusicMessage { public function __construct( public string $clockMusic ) { } } // src/MessageHandler/PlayMusicMessageHandler.php #[ AsMessageHandler ] final class PlayMusicMessageHandler { public function __invoke( PlayMusicMessage $message): void { $command = sprintf('mplayer %s', $message->clockMusic); } } shell_exec($command);
  8. How to use Intermediate level (2/2) // ... // src/Scheduler/ClockSchedule.php

    #[ AsSchedule ] final class ClockSchedule implements ScheduleProviderInterface { public function getSchedule(): Schedule { $from = new \DateTimeImmutable ('07:30', new \DateTimeZone ('Europe/Paris')); } } return (new Schedule ()) ->add( RecurringMessage ::every('1 day', new PlayMusicMessage ($clockMusic), $from)) ;
  9. How to use Advanced level (1/3) // src/Scheduler/Trigger/ExcludePublicHolidaysTrigger.php final class

    ExcludePublicHolidaysTrigger implements TriggerInterface { public function __construct( private readonly TriggerInterface $inner, // ... ) { } public function __toString(): string { return sprintf('%s (except public holidays)', $this ->inner); } private function isPublicHoliday( \DateTimeImmutable $timestamp): bool { // check if it's a public holiday }
  10. How to use Advanced level (2/3) // ... public function

    getNextRunDate( \DateTimeImmutable $run): ? \DateTimeImmutable { $nextRun = $this ->inner->getNextRunDate($run); if (null === $nextRun) { return null; } // loop until you get the next run date that is not a public holiday while ( $this ->isPublicHoliday($nextRun)) { $nextRun = $this ->inner->getNextRunDate($nextRun); } } } return $nextRun;
  11. How to use Advanced level (3/3) // ... // src/Scheduler/ClockSchedule.php

    #[ AsSchedule ] final class ClockSchedule implements ScheduleProviderInterface { public function getSchedule(): Schedule { $from = new \DateTimeImmutable ('07:30', new \DateTimeZone ('Europe/Paris')); } } return $this ->schedule ??= (new Schedule ()) ->with( RecurringMessage::trigger( new ExcludePublicHolidaysTrigger ( new PeriodicalTrigger ('1 day', $from), // ... ), new PlayMusicMessage ($clockMusic) ), ) ;
  12. Debugging our Schedules Easy level $ faketime '2024-05-22 18:30:30' bin/console

    debug:scheduler Scheduler ========= default ---------------------- ------------------------------------------------------------------- --------------------------------Trigger Provider Next Run ---------------- ------------------------------------------------------------------- --------------------------------every 1 minute Symfony\Component\Console\Messenger\RunCommandMessage (app:clock) Wed, 22 May 2024 18:31:00 +0200 ---------------- ------------------------------------------------------------------- ---------------------------------
  13. Debugging our Schedules Intermediate level $ faketime '2024-05-19 09:00:00' bin/console

    debug:scheduler Scheduler ========= default ------------------- ------------------------------ --------------------------------Trigger Provider Next Run ------------- ------------------------------ --------------------------------every 1 day App\Message\PlayMusicMessage Mon, 20 May 2024 07:30:00 +0200 ------------- ------------------------------ ---------------------------------
  14. Debugging our Schedules Advanced level $ faketime '2024-05-19 09:00:00' bin/console

    debug:scheduler Scheduler ========= default -------------------------------------------- ------------------------------ --------------------------------Trigger Provider Next Run -------------------------------------- ------------------------------ --------------------------------every 1 day (except public holidays) App\Message\PlayMusicMessage Tue, 21 May 2024 07:30:00 +0200 -------------------------------------- ------------------------------ ---------------------------------
  15. Triggers RecurringMessage::every('1 second', new Message()); RecurringMessage::every('15 days', new Message()); #

    relative format RecurringMessage::every('next friday', new Message()); RecurringMessage::every('first Monday of next month', new Message()); # run at a very specific time every day RecurringMessage::every('1 day', new Message(), from: '14:42'); # you can pass full date/time objects too RecurringMessage::every('1 day', new Message(), from: new \DateTimeImmutable('14:42', new \DateTimeZone('Europe/Paris'))); # define the end of the handling too RecurringMessage::every('1 day', new Message(), until: '2023-09-21'); # you can even use cron expressions RecurringMessage::cron('* * * * *', new Message()); // every minute RecurringMessage::cron('42 14 * * 2', new Message()); // every Tuesday at 14:42 For cron triggers you need to install: dragonmantank/cronexpression
  16. Jitter 0 2 * * * 4 2 * *

    * 30 4 * * * 38 4 * * * JitterTrigger public function getNextRunDate( \DateTimeImmutable $run): ? \DateTimeImmutable { if (!$nextRun = $this ->trigger->getNextRunDate($run)) { return null; } } return $nextRun->add(new \DateInterval (sprintf('PT%sS', random_int(0, $this ->maxSeconds))));
  17. Cron Pros A reliable solution for more than half a

    century Ease of use Cost-effective Lightweight Cons No end date Outside the application Smallest resolution is 1 minute Requires Unix/Linux skills
  18. Scheduler Pros Automation is managed by your application Fine-grain control

    of task recurrence (1 second precision) Until Ready to use when you use Messenger Cons Requires Messenger
  19. Links Keynote: The Scheduler Component Master task scheduling with Symfony

    Scheduler New in Symfony 6.3: Scheduler Component Scheduler Component Scheduler