-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Messenger] Add a scheduler component #47112
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
Hi 👋🏻 As
Regarding
Actually, it depends, talking about
In the end, running the task via the worker of |
Nice to meet you, @Guikingone 👋 I've mentioned
But it requires a way to launch tasks! Without running e.g. class ScheduleFactory {
public static function createSchedule(ClockInterface $clock){
return new \Symfony\Component\Messenger\Bridge\Scheduler\Transport\Schedule(
$clock,
PeriodicalJob::infinite('00:00:00', 'PT1M', new EveryMinuteJob()),
);
}
} #[AsMessageHandler]
class EveryMinuteHandler {
public function __construct(private readonly ScheduleRunner $scheduleRunner) {
}
public function __invoke(EveryMinuteJob $job){
($this->scheduleRunner)();
}
}
Yes, it's possible to write some custom worker with UPDATE |
Nevertheless, there is a nuance... Hm... there are few ones 😁 Why is some Schedule/Cron/Jobs/Tasks/Etc bundle is needed when the crond/cronspec/CronJob/cronetc is already exists? Why do not configure a crontab/CloudSpec/Helm/Etc to run tasks? The answer is: because it is necessary to control the application's tasks in the application itself, not by infrastructure. The first nuance is the Messenger is in the application already (no needs to launch anything dependent on time). |
I like this idea, been able to keep the application code together, having all "Schedule/Queue" tasks together helps with maintainability and without needing crond would be a very nice touch to have in some container setups. |
@upyx I like it a lot :) |
@Guikingone I was cofused with zenstruck's bundle and yours, sorry for that. A broken link in the issue (#39719) supports doing mistakes like that. @fabpot I'll prepare PR for review in few days. |
No problem 😅 I tend to have a pretty different vision of why a scheduler worker is different from a message queue one (in particular when it comes to consuming tasks, handling failure, transports, limits, middleware and so on), in the end, the way the linux scheduler handles tasks is not the same as RabbitMQ or even Kafka but that's a complete separate topic from the current one 🙂 |
4fb1889
to
b65a683
Compare
Ready for feedback ✍️ Few questions:
|
I understand what you are saying about. Despite much in common, message processing and task scheduling are completely different things. It matters when we design an application that deals with realtime signals like a shooter game or an audio editor. It matters when we plan a distributed application like Telegram. When the only thing that is needed is to create a new table partition every week, I tend to save a few key presses and some space in the vendor directory. |
@upyx Bridges are only helpful when a feature depends on a third-party service/prodiver. Here, that's not the case, so I would move the code to the "core" of the component instead. |
b65a683
to
5e9664d
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.
I still need to play with it a bit more, but I like the simplicity of this approach.
I've made some renaming suggestions.
Would it sense to deprecate DelayStamp
as it does something similar?
src/Symfony/Component/Messenger/Transport/Schedule/JobScheduleInterface.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Schedule/PeriodicalJob.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Schedule/PeriodicalJob.php
Outdated
Show resolved
Hide resolved
31f0f16
to
4be42d9
Compare
I have used the new Clock component. How to properly add a dependency of that? |
You should add it as a |
src/Symfony/Component/Messenger/Transport/Schedule/PeriodicalMessage.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Schedule/PeriodicalMessage.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Schedule/ScheduleTransportFactory.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Schedule/Schedule.php
Outdated
Show resolved
Hide resolved
src/Symfony/Component/Messenger/Transport/Schedule/ScheduleTransport.php
Outdated
Show resolved
Hide resolved
ca924f7
to
82a2682
Compare
Still one issue we need to fix... WIP |
82a2682
to
a499641
Compare
src/Symfony/Component/Scheduler/Tests/Messenger/SchedulerTransportTest.php
Outdated
Show resolved
Hide resolved
ae88cdd
to
3b205a7
Compare
$this->assertSame([$foo], $fetchMessages(1.0)); | ||
$this->assertSame([], $fetchMessages(1.0)); | ||
$this->assertSame([$bar], $fetchMessages(60.0)); | ||
$this->assertSame([$foo, $bar, $foo, $bar], $fetchMessages(600.0)); |
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.
Tests are green but this result is suspicious, isn't it?
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'll check. It's funtional, and it's a sequence of "runs".
3b205a7
to
a054802
Compare
src/Symfony/Component/Scheduler/Messenger/SchedulerTransport.php
Outdated
Show resolved
Hide resolved
public function get(): iterable | ||
{ | ||
foreach ($this->messageGenerator->getMessages() as $message) { | ||
yield Envelope::wrap($message, [new ScheduledStamp()]); |
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.
Was better. All instances of ScheduledStamp
are the same, so can be reused.
f1f9a90
to
32cbe20
Compare
32cbe20
to
a18127b
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.
Let's merge and iterate!
Thank you @upyx. |
Thank you Fabien! I'm proud to have been working with you 🙂 |
Introdution
There is no easy way to schedule periodical tasks. There are few useful tools which I touched:
They are complicated. They doesn't allow to set time with precision in seconds (at least it isn't easy). They require difficult tricks to set not linear periods (like on sunset in Tokyo).
They arePart of them inefficient with infrequent tasks because resources are needed on every run (e.g. Kubernetes CronJob creates and destroes an entire container).Proposal
I use a custom transport of Messenger that generates messages periodically. It's a simple solution to run periodical jobs without external software. It's especially helpful in environments where additional runners are impossible or very painful (like Kubernetes). Configuration is very flexible and accurate, it's possible to configure any rules when to run or not to run.
Compared to
crond
: there is no need to install something external, precision of schedule in microseconds instead of minutes, it's possible to set any periods.Simple example
Few types of messages:
A handlers:
A schedules are provided by locators. It's possible to create many locators and/or provide many schedules by the same locator:
To run schedule:
It's easy to run jobs manually:
Example with returning a result
Configuring
A minimal configuration:
More complex example:
Example HA configuration with redis:
Deprecations
None
Implementation
This PR contains an implementation.
ToDo
CHANGELOG
s &README
s