Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[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

Conversation

alli83
Copy link
Contributor

@alli83 alli83 commented Dec 9, 2023

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

@carsonbot carsonbot added this to the 6.3 milestone Dec 9, 2023
@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch from ee04bd0 to 360f745 Compare December 9, 2023 13:37
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.
Copy link
Member

@kbond kbond Dec 9, 2023

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
    }
}

@kbond
Copy link
Member

kbond commented Dec 9, 2023

When documenting "hashed cron expressions", this documentation that explains the spec can be adapted.

@alexandre-daubois
Copy link
Member

Let's not forget about the versionadded directive 🙂 Like this

@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch 3 times, most recently from 7a7f7ac to 33ead7e Compare December 13, 2023 07:22
Copy link
Member

@alexandre-daubois alexandre-daubois left a 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.
Copy link
Member

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
{
...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
...
// ...

scheduler.rst Outdated
Comment on lines 98 to 142
A message associated with a Trigger
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copy link
Member

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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
RecurringMessage::cron(*****, new Message())
RecurringMessage::cron('*****', new Message());

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
Copy link
Member

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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
Copy link
Member

@kbond kbond Dec 13, 2023

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:
Copy link
Member

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.

@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch 16 times, most recently from 3a73ea3 to 1acf6bf Compare December 14, 2023 14:43
@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch 3 times, most recently from bf26c53 to d7e8358 Compare December 14, 2023 15:05
@alli83
Copy link
Contributor Author

alli83 commented Dec 14, 2023

I'll add a link to redirect to cache and lock

@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch from d7e8358 to ee40bad Compare December 14, 2023 15:17
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.
Copy link
Contributor

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 ?

Copy link
Contributor

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
Copy link
Contributor

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.
Copy link
Contributor

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,
Copy link
Contributor

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
Copy link
Contributor

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

@MrYamous
Copy link
Contributor

Congrats for your work on this doc :)

@alli83
Copy link
Contributor Author

alli83 commented Dec 14, 2023

@MrYamous Indeed, I've kind of overlooked the version differences 😅. I'll include them in versionadded notes
And I'll open a new PR on 6.4 for the Dynamic schedule part

@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch from ee40bad to 3dbb65f Compare December 15, 2023 03:29
@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch 3 times, most recently from f51d927 to d0a0dc8 Compare December 15, 2023 05:05
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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
Copy link
Member

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.
Copy link
Member

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.

Copy link
Contributor Author

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
Copy link
Member

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
Copy link
Member

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
Copy link
Member

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())
Copy link
Member

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,
Copy link
Member

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.

@alli83
Copy link
Contributor Author

alli83 commented Dec 20, 2023

@weaverryan thanks for the feedback! I'll update it and ping you

@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch 5 times, most recently from dcd5bb9 to 72eff06 Compare December 21, 2023 07:13
Comment on lines +159 to +161
.. versionadded:: 6.4

Since version 6.4, it is now possible to add and define a timezone as a 3rd argument
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. 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

Copy link
Contributor Author

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

Comment on lines +260 to +284
.. 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. 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.

@alli83 alli83 force-pushed the symfony-scheduler-doc-draft-skeleton-proposal branch from 72eff06 to b50df97 Compare December 21, 2023 07:47
@javiereguiluz
Copy link
Member

@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.

@javiereguiluz javiereguiluz merged commit c128105 into symfony:6.3 Jan 16, 2024
@alexandre-daubois
Copy link
Member

Congrats @alli83!

@alli83
Copy link
Contributor Author

alli83 commented Jan 16, 2024

@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.

Ok thx for all your feedback. second part (6.4) is here #19292

javiereguiluz added a commit that referenced this pull request Jan 23, 2024
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants