WEBVTT

NOTE Created by CaptionSync from Automatic Sync Technologies www.automaticsync.com

00:00:01.066 --> 00:00:02.266 align:middle
Hey! You're still here?

00:00:02.496 --> 00:00:04.606 align:middle
Great! I have a bonus chapter for you.

00:00:05.256 --> 00:00:09.306 align:middle
One of our interns, Hugo, is complaining
that he has to log in to our server

00:00:09.466 --> 00:00:12.326 align:middle
and run the booking reminders
command, every night at midnight.

00:00:12.396 --> 00:00:15.846 align:middle
I don't know what the problem is -
isn't that what interns are for?!

00:00:16.706 --> 00:00:21.946 align:middle
But... I guess to be more robust, we should
automate this in case he's sick or forgets.

00:00:21.946 --> 00:00:23.606 align:middle
We could set up a CRON job...

00:00:23.946 --> 00:00:28.506 align:middle
but that wouldn't be nearly as cool or flexible
as using the Symfony Scheduler component.

00:00:28.676 --> 00:00:30.536 align:middle
It's perfect for this.

00:00:30.536 --> 00:00:34.866 align:middle
At your terminal, run: composer
require scheduler Think

00:00:34.866 --> 00:00:37.556 align:middle
of Symfony Scheduler as an add-on for Messenger.

00:00:38.026 --> 00:00:41.716 align:middle
It provides its own special
transport that, instead of a queue,

00:00:41.766 --> 00:00:43.846 align:middle
determines if it's time to run a job.

00:00:44.496 --> 00:00:49.396 align:middle
Each job, or task, is a messenger
message, so it requires a message handler.

00:00:50.186 --> 00:00:54.856 align:middle
You consume the schedule, like any messenger
transport with the messenger:consume command.

00:00:55.296 --> 00:01:01.176 align:middle
Create a schedule with: symfony
console make:schedule Transport name?

00:01:01.336 --> 00:01:02.186 align:middle
Use default.

00:01:02.576 --> 00:01:03.376 align:middle
Schedule name?

00:01:03.526 --> 00:01:05.276 align:middle
Use the default: MainSchedule.

00:01:05.526 --> 00:01:08.696 align:middle
Exciting! It's possible to
have multiple schedules,

00:01:08.916 --> 00:01:11.846 align:middle
but for most apps, a single schedule is enough.

00:01:11.846 --> 00:01:15.436 align:middle
Check it out: src/Scheduler/MainSchedule.php.

00:01:15.436 --> 00:01:20.126 align:middle
It's a service that implements
ScheduleProviderInterface and is marked

00:01:20.126 --> 00:01:23.286 align:middle
with the #[AsSchedule] attribute
with the name default.

00:01:25.046 --> 00:01:28.816 align:middle
The maker automatically injected the
cache, and we'll see why in a second.

00:01:29.446 --> 00:01:33.346 align:middle
The getSchedule() method is where we
configure the schedule and add tasks.

00:01:33.876 --> 00:01:38.136 align:middle
This -&gt;stateful() that we're passing
$this-&gt;cache to is important.

00:01:38.136 --> 00:01:41.326 align:middle
If the process that's running
this schedule goes down -

00:01:41.476 --> 00:01:44.916 align:middle
like our messenger workers stop
temporarily during a server restart -

00:01:45.316 --> 00:01:49.016 align:middle
when it comes back online, it will know
all the jobs it missed and run them.

00:01:49.016 --> 00:01:53.656 align:middle
If a task was supposed to run 10 times
while it was down, it will run them all.

00:01:53.926 --> 00:01:59.716 align:middle
That might not be desired so add
-&gt;processOnlyLastMissedRun(true)

00:02:00.066 --> 00:02:02.426 align:middle
to only run the last one: Bulletproof!

00:02:02.566 --> 00:02:07.626 align:middle
For more complex apps, you might be consuming
the same schedule on multiple workers.

00:02:08.226 --> 00:02:13.056 align:middle
Use -&gt;lock() to configure a lock so that
only one worker runs the task when its due.

00:02:13.976 --> 00:02:15.346 align:middle
Time to add our first task!

00:02:16.006 --> 00:02:19.006 align:middle
In -&gt;add(), write RecurringMessage::.

00:02:19.106 --> 00:02:22.636 align:middle
There are a few different
ways to trigger a task.

00:02:22.936 --> 00:02:24.116 align:middle
I like to use cron().

00:02:24.886 --> 00:02:27.386 align:middle
I want this task to run at midnight, every day,

00:02:27.566 --> 00:02:34.616 align:middle
so use 0 0 * * *. The second argument
is the messenger message to dispatch.

00:02:34.876 --> 00:02:38.946 align:middle
We want to run the SendBookingRemindersCommand,
but we can't add it here directly.

00:02:38.946 --> 00:02:43.796 align:middle
Instead, use new RunCommandMessage()
and pass the command name:

00:02:44.066 --> 00:02:48.326 align:middle
app:send-booking-reminders (you can
pass arguments and options here too):

00:02:49.086 --> 00:02:52.066 align:middle
At your terminal, list our
schedule's tasks by running:

00:02:52.066 --> 00:02:56.426 align:middle
symfony console debug:schedule
Oh, we have an error.

00:02:56.736 --> 00:02:59.226 align:middle
You cannot use "CronExpressionTrigger" as the

00:02:59.226 --> 00:03:05.006 align:middle
"cron expression" package is not installed
Easy fix: copy the install command and run it:

00:03:06.316 --> 00:03:10.906 align:middle
composer require dragonmantank/cron-expression
Cool name!

00:03:12.066 --> 00:03:18.936 align:middle
Now run the debug command again: Here we go, the
output's a little wonky on this small screen,

00:03:19.226 --> 00:03:22.656 align:middle
but you can see the cron
expression, the message (and command),

00:03:22.656 --> 00:03:25.136 align:middle
and the next runtime: tonight at midnight.

00:03:26.496 --> 00:03:28.436 align:middle
There's an alternate to schedule commands.

00:03:29.036 --> 00:03:32.176 align:middle
In MainSchedule::getSchedule(),
delete the -&gt;add().

00:03:32.646 --> 00:03:35.206 align:middle
Then jump over to our
SendBookingRemindersCommand

00:03:35.446 --> 00:03:41.676 align:middle
and add another attribute: #[AsCronTask()]
passing: 0 0 * * *: In your terminal,

00:03:42.466 --> 00:03:47.826 align:middle
debug the schedule again to make sure
it's still listed: And it is, pretty neat.

00:03:47.826 --> 00:03:51.726 align:middle
If you have a lot of tasks scheduled
at the same time, like midnight,

00:03:51.906 --> 00:03:54.566 align:middle
you might see a CPU spike
at this time on your server.

00:03:55.136 --> 00:03:59.856 align:middle
Unless it's super important that tasks run at a
very specific time, you should spread them out.

00:04:00.576 --> 00:04:03.986 align:middle
One way to do this of course, is to manually
make sure they all have different cron

00:04:03.986 --> 00:04:05.126 align:middle
expressions but...

00:04:05.296 --> 00:04:05.986 align:middle
that's a bore.

00:04:05.986 --> 00:04:09.136 align:middle
For our app:send-booking-reminders command,

00:04:09.256 --> 00:04:12.146 align:middle
I don't care when it runs,
just that it runs once a day.

00:04:12.706 --> 00:04:14.826 align:middle
We can use a hashed cron expression.

00:04:15.456 --> 00:04:18.306 align:middle
In our expression, replace the 0's with #'s.

00:04:18.836 --> 00:04:22.106 align:middle
The # means "pick a random,
valid value for this part":

00:04:23.966 --> 00:04:28.576 align:middle
Debug the schedule again:
It's set to run at 5:11am.

00:04:30.286 --> 00:04:33.386 align:middle
Run the command again: It's still 5:11am.

00:04:33.856 --> 00:04:38.986 align:middle
Ok, so it's not truly random, the values
are calculated deterministically based

00:04:38.986 --> 00:04:40.216 align:middle
on the message details.

00:04:40.646 --> 00:04:44.166 align:middle
In our case, the string
app:send-booking-reminders.

00:04:44.296 --> 00:04:47.906 align:middle
A different command with the same hash
expression will have different values.

00:04:48.666 --> 00:04:51.406 align:middle
The Scheduler documentation
has all the details on this.

00:04:52.136 --> 00:04:54.396 align:middle
There's even aliases for common hashes.

00:04:54.476 --> 00:04:58.326 align:middle
For instance, #mignight will pick
a time between midnight and 3am.

00:04:58.806 --> 00:05:06.356 align:middle
Use that for our expression: and debug the
schedule again: Oops, a typo, I'll fix that

00:05:06.356 --> 00:05:14.736 align:middle
and run again: It's now scheduled
to run every day at 2:11am.

00:05:15.006 --> 00:05:18.356 align:middle
Cool! We've configured our
schedule, but how do we run it?

00:05:18.906 --> 00:05:21.756 align:middle
Remember, schedules are just
Messenger transports.

00:05:22.266 --> 00:05:28.926 align:middle
The transport name is scheduler_&lt;schedule_name&gt;,
in our case, scheduler_default.

00:05:29.426 --> 00:05:36.846 align:middle
Run it with: symfony console messenger:consume
scheduler_default On your production server,

00:05:36.846 --> 00:05:40.386 align:middle
configure this to run in the background
just like a normal messenger worker.

00:05:41.236 --> 00:05:44.166 align:middle
Alright, that's a quick rundown
of the Scheduler component.

00:05:44.496 --> 00:05:46.786 align:middle
Check out the documentation
to learn more about it!

00:05:47.196 --> 00:05:49.286 align:middle
Happy coding and happy scheduling!

