-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
[Scheduler] Proposal - initial structure for Symfony Scheduler documentation #19244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Scheduler] Proposal - initial structure for Symfony Scheduler documentation #19244
Conversation
ee04bd0
to
360f745
Compare
scheduler.rst
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything can of course be discussed 😄 You should also try to break your lines at 80 characters. Congrats for this great work already 👏
scheduler.rst
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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"
scheduler.rst
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
scheduler.rst
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: |
scheduler.rst
Outdated
{ | ||
public function getSchedule(): Schedule | ||
{ | ||
... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... | |
// ... |
scheduler.rst
Outdated
A message associated with a Trigger | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this title can be removed
scheduler.rst
Outdated
|
||
.. code-block:: php | ||
|
||
RecurringMessage::cron(‘*****’, new Message()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RecurringMessage::cron(‘*****’, new Message()) | |
RecurringMessage::cron('*****', new Message()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RecurringMessage::cron(‘*****’, new Message()) | |
RecurringMessage::cron('* * * * *', new Message()) |
(spaces between are required)
scheduler.rst
Outdated
|
||
.. tip:: | ||
|
||
It's possible to add and define a timezone as a 3rd argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may actually put this in the code snippet above, something like
// optionally specify the timezone to run the job on
RecurringMessage::cron...
scheduler.rst
Outdated
|
||
.. code-block:: php | ||
|
||
RecurringMessage::cron(‘*****’, new Message()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RecurringMessage::cron(‘*****’, new Message()) | |
RecurringMessage::cron('* * * * *', new Message()) |
(spaces between are required)
scheduler.rst
Outdated
|
||
.. tip:: | ||
|
||
A hashed expressions is a string representing the schedule for a particular command to execute. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
scheduler.rst
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The --all
option has been added in 6.4. Maybe we should keep it for another PR ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like --date
has been added at the same time, 6.4 too
scheduler.rst
Outdated
|
||
.. tip:: | ||
|
||
It's possible to add and define a timezone as a 3rd argument |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIUC, timezone for cron expression trigger is a 6.4 feature
scheduler.rst
Outdated
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those attributes have been added in 6.4
scheduler.rst
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Methods remove
and clear
have been added in 6.4
scheduler.rst
Outdated
~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
scheduler.rst
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
scheduler.rst
Outdated
|
||
$ composer require symfony/scheduler | ||
|
||
Debugging the Schedule |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this later. I haven't learned how to create recurring message yet.
scheduler.rst
Outdated
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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'
scheduler.rst
Outdated
// src/Scheduler/MyScheduleProvider.php | ||
namespace App\Scheduler; | ||
|
||
class MyScheduleProvider implements ScheduleProviderInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
scheduler.rst
Outdated
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.. 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