[Scheduler] Proposal - initial structure for Symfony Scheduler documentation#19244
Conversation
ee04bd0 to
360f745
Compare
| A message associated with a Trigger | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| - The importance of setting the frequency for your messages: Introduce the concept of a Trigger in Symfony Scheduler encompassing all the different types. |
There was a problem hiding this comment.
When covering custom triggers, an interesting example could be a trigger wrapper that excludes holidays: Cron task that runs every weekday at midnight, except "holidays" (defined by some kind of lookup table).
RecurringMessage::trigger(
new ExcludeHolidaysTrigger( // our custom trigger wrapper
CronExpressionTrigger::fromSpec('@daily'),
),
new SendDailySalesReports(),
);And something like the following for the custom trigger (untested):
class ExcludeHolidaysTrigger implements TriggerInterface
{
public function __construct(private TriggerInterface $inner)
{
}
public function __toString(): string
{
return $this->inner.' (except holidays)';
}
public function getNextRunDate(\DateTimeImmutable $run): ?\DateTimeImmutable
{
if (!$nextRun = $this->inner->getNextRunDate($run)) {
return null;
}
while (!$this->isHoliday($nextRun) { // loop until we get the next run date that is not a holiday
$nextRun = $this->inner->getNextRunDate($nextRun);
}
return $nextRun;
}
private function isHoliday(\DateTimeImmutable $timestamp): bool
{
// app specific logic to determine if $timestamp is on a holiday
// returns true if holiday, false otherwise
}
}|
When documenting "hashed cron expressions", this documentation that explains the spec can be adapted. |
|
Let's not forget about the |
7a7f7ac to
33ead7e
Compare
alexandre-daubois
left a comment
There was a problem hiding this comment.
Everything can of course be discussed 😄 You should also try to break your lines at 80 characters. Congrats for this great work already 👏
| Introduction to the case: | ||
| ------------------------- | ||
|
|
||
| Embarking on a task is one thing, but often, the need to repeat that task looms large. While one could resort to issuing commands and scheduling them with cron jobs, this approach involves external tools and additional configuration. The Symfony Scheduler component emerges as a solution, allowing us to retain control, configuration, and maintenance of task scheduling within our PHP application. |
There was a problem hiding this comment.
As far as I am aware, we never use "us". You may replace by "allowing you to retain control". Same for "our", to be replace by "your"
| At its core, the principle is straightforward: a task, considered as a message needs to be managed by a service, and this cycle must be repeated. | ||
| Does this sound familiar? Think :doc:`Symfony Messenger docs </components/messenger>`. | ||
|
|
||
| But while the system of Symfony Messenger proves very useful in various scenarios, there are instances where its capabilities fall short, particularly when dealing with repetitive tasks at regular intervals. |
There was a problem hiding this comment.
| But while the system of Symfony Messenger proves very useful in various scenarios, there are instances where its capabilities fall short, particularly when dealing with repetitive tasks at regular intervals. | |
| While the system of Messenger proves very useful in various scenarios, there are instances where its capabilities fall short, particularly when dealing with repetitive tasks at regular intervals. |
|
|
||
| Let's dive into a practical example within the context of a sales company. | ||
|
|
||
| Imagine the company's goal is to send diverse sales reports to customers based on the specific reports each customer chooses to receive. In constructing the schedule for this scenario, the following steps are taken: |
There was a problem hiding this comment.
| Imagine the company's goal is to send diverse sales reports to customers based on the specific reports each customer chooses to receive. In constructing the schedule for this scenario, the following steps are taken: | |
| Let's imagine the company's goal is to send diverse sales reports to customers based on the specific reports each customer chooses to receive. In constructing the schedule for this scenario, the following steps are taken: |
| { | ||
| public function getSchedule(): Schedule | ||
| { | ||
| ... |
There was a problem hiding this comment.
| ... | |
| // ... |
| A message associated with a Trigger | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
I think this title can be removed
|
|
||
| .. code-block:: php | ||
|
|
||
| RecurringMessage::cron(‘*****’, new Message()) |
There was a problem hiding this comment.
| RecurringMessage::cron(‘*****’, new Message()) | |
| RecurringMessage::cron('*****', new Message()); |
There was a problem hiding this comment.
| RecurringMessage::cron(‘*****’, new Message()) | |
| RecurringMessage::cron('* * * * *', new Message()) |
(spaces between are required)
|
|
||
| .. tip:: | ||
|
|
||
| It's possible to add and define a timezone as a 3rd argument |
There was a problem hiding this comment.
You may actually put this in the code snippet above, something like
// optionally specify the timezone to run the job on
RecurringMessage::cron...
|
|
||
| .. code-block:: php | ||
|
|
||
| RecurringMessage::cron(‘*****’, new Message()) |
There was a problem hiding this comment.
| RecurringMessage::cron(‘*****’, new Message()) | |
| RecurringMessage::cron('* * * * *', new Message()) |
(spaces between are required)
|
|
||
| .. tip:: | ||
|
|
||
| A hashed expressions is a string representing the schedule for a particular command to execute. |
There was a problem hiding this comment.
This part isn't quite correct. What you're describing is the standard cron aliases
@daily@monthly- etc...
Hashed aliases are different in that they create a random but deterministic standard cron expression based on some context (in this case, the message's __toString() value).
At some point later in the doc, we need to discuss the importance of not having many tasks all run at the same time (ie 10 jobs at 00:00 every day). The jitter trigger wrapper is one solution, another is hashed cron expressions. I think here is where we should describe this feature.
Why don't you drop this section for now (or just show more examples of standard cron expressions) and I'll create a follow-up PR explaining hashed expressions. I originally ported this code to Symfony and use it quite extensively.
|
|
||
| The trigger is what allows configuring the recurrence frequency of your message. Several options are available to us: | ||
|
|
||
| #. It can be a cron expression trigger: |
There was a problem hiding this comment.
We need to note that dragonmantank/cron-expression is required to use the cron expression trigger.
Might also be nice to have a link to https://crontab.guru/ to help users construct/understand cron expressions.
3a73ea3 to
1acf6bf
Compare
bf26c53 to
d7e8358
Compare
|
I'll add a link to redirect to cache and lock |
d7e8358 to
ee40bad
Compare
| The ``debug:scheduler`` command provides a list of schedules along with their recurring messages. | ||
|
|
||
| You can narrow down the list to a specific schedule, or even specify a date to determine the next run date using the ``--date`` option. | ||
| Additionally, you have the option to display terminated recurring messages using the ``--all`` option. |
There was a problem hiding this comment.
The --all option has been added in 6.4. Maybe we should keep it for another PR ?
There was a problem hiding this comment.
Seems like --date has been added at the same time, 6.4 too
|
|
||
| .. tip:: | ||
|
|
||
| It's possible to add and define a timezone as a 3rd argument |
There was a problem hiding this comment.
IIUC, timezone for cron expression trigger is a 6.4 feature
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| There is also another way to build a RecurringMessage, and this can be done simply by adding an attribute above a service or a command: | ||
| :class:`Symfony\\Component\\Scheduler\\Attribute\\AsPeriodicTask` attribute and :class:`Symfony\\Component\\Scheduler\\Attribute\\AsCronTask` attribute. |
There was a problem hiding this comment.
Those attributes have been added in 6.4
| Exploring Strategies for adding, removing, and modifying entries within the Schedule | ||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| The schedule provides you with the ability to :method:`Symfony\\Component\\Scheduler\Schedule::add`, :method:`Symfony\\Component\\Scheduler\Schedule::remove`, or :method:`Symfony\\Component\\Scheduler\Schedule::clear` all associated RecurringMessages, |
There was a problem hiding this comment.
Methods remove and clear have been added in 6.4
| ~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| The goal is to provide flexibility in deciding when to take action while preserving decoupling. | ||
| Three primary event types have been introduced types |
There was a problem hiding this comment.
Events have been added in 6.4
|
Congrats for your work on this doc :) |
|
@MrYamous Indeed, I've kind of overlooked the version differences 😅. I'll include them in versionadded notes |
ee40bad to
3dbb65f
Compare
f51d927 to
d0a0dc8
Compare
|
|
||
| The Scheduler component was introduced in Symfony 6.3 | ||
|
|
||
| The Symfony Scheduler is a powerful and flexible component designed to manage tasks scheduling within your PHP application. |
There was a problem hiding this comment.
| The Symfony Scheduler is a powerful and flexible component designed to manage tasks scheduling within your PHP application. | |
| Scheduler is a component designed to manage task scheduling within your PHP application - like running a task each night at 3 am, every 2 weeks except for holidays or any schedule you can imagine. |
|
|
||
| $ composer require symfony/scheduler | ||
|
|
||
| Debugging the Schedule |
There was a problem hiding this comment.
Let's move this later. I haven't learned how to create recurring message yet.
|
|
||
| The Scheduler component emerges as a solution, allowing you to retain control, configuration, and maintenance of task scheduling within our PHP application. | ||
|
|
||
| At its core, the principle is straightforward: a task, considered as a message needs to be managed by a service, and this cycle must be repeated. |
There was a problem hiding this comment.
The "considered as a message" doesn't make sense to me. Does schedule call them "messages" but the user thinks of them as tasks? If so, how about:
At its core, scheduler allows you to create a task (called a message) that is executed by a service and repeated on some schedule.
There was a problem hiding this comment.
I understand your point of view. Indeed, what I meant to say is: 'At its core, the principle is straightforward: a task, treated as a message by the Scheduler, must be handled by a service, and this cycle should be repeated'
| // src/Scheduler/MyScheduleProvider.php | ||
| namespace App\Scheduler; | ||
|
|
||
| class MyScheduleProvider implements ScheduleProviderInterface |
There was a problem hiding this comment.
If we can think of a more realistic name, that would be awesome :)
|
|
||
| .. tip:: | ||
|
|
||
| It is a good practice to memoize your schedule to prevent unnecessary reconstruction if the ``getSchedule`` method is checked by another service or internally within Symfony |
There was a problem hiding this comment.
I'm not sure we should mention this. Memoizing is a pretty technical term and probably creating a schedule is not a heavy thing anyway.
| It is a good practice to memoize your schedule to prevent unnecessary reconstruction if the ``getSchedule`` method is checked by another service or internally within Symfony | ||
|
|
||
|
|
||
| The Concept of RecurringMessage in Scheduler |
There was a problem hiding this comment.
Are there any other types of messages that you would schedule? Suggestion for the title:
Scheduling Recurring Messages
And, I like this section. This is where we get into the meat of things
| { | ||
| public function getSchedule(): Schedule | ||
| { | ||
| return $this->schedule ??= (new Schedule()) |
There was a problem hiding this comment.
Is the $this->schedule part of the memoization? I really need to be convinced that it is VERY important to keep this detail
| Efficient management with Symfony Scheduler | ||
| ------------------------------------------- | ||
|
|
||
| However, if your worker becomes idle, since the messages from your schedule are generated on-the-fly by the schedulerTransport, |
There was a problem hiding this comment.
We haven't talked about workers or messenger:consume yet. I think we should at least show them. The story I want to see is:
A) Creating a message & handler of some sort (this can be very quick and point to Messenger, and the handler can be empty, but we should show it)
B) Creating a schedule and setting up this message in a recurring way
C) Running messenger:consume - and talking a bit about how that works and what to expect.
|
@weaverryan thanks for the feedback! I'll update it and ping you |
dcd5bb9 to
72eff06
Compare
| .. versionadded:: 6.4 | ||
|
|
||
| Since version 6.4, it is now possible to add and define a timezone as a 3rd argument |
There was a problem hiding this comment.
| .. versionadded:: 6.4 | |
| Since version 6.4, it is now possible to add and define a timezone as a 3rd argument |
To keep for 6.4 PR
There was a problem hiding this comment.
#19244 (comment)
It'll be updated in #19292 + version added in 6.3
| .. versionadded:: 6.4 | ||
|
|
||
| Since version 6.4, you can even specify a date to determine the next run date using the ``--date`` option. | ||
| Additionally, you have the option to display terminated recurring messages using the ``--all`` option. |
There was a problem hiding this comment.
| .. versionadded:: 6.4 | |
| Since version 6.4, you can even specify a date to determine the next run date using the ``--date`` option. | |
| Additionally, you have the option to display terminated recurring messages using the ``--all`` option. |
72eff06 to
b50df97
Compare
|
@alli83 we've finally decided to merge your PR "as is". In a different PR we're going to make some of the changes proposed by the reviewers. Thanks a lot for your contribution to kickstart these docs and thanks to all reviewers too. |
|
Congrats @alli83! |
This PR was merged into the 6.4 branch. Discussion ---------- [Scheduler] doc draft dynamic schedule following #19244, this section of the documentation focuses on the dynamic aspect of the Schedule: the ability to modify a Schedule by adding or removing recurringMessages. It also introduces another way to create a RecurringMessage using two attributes Commits ------- 33f5017 [Scheduler] doc draft dynamic schedule
Proposal: initial structure for Symfony Scheduler documentation
This pull request serves as a proposal for the documentation plan of the Scheduler component. The objective is to make it dynamic, focusing on a use case and exploring all the necessary setups and operational details.
The goal is to mirror the thought process one would undergo when implementing the component for a use case.
second part (6.4) #19292