schedule-bundle
schedule-bundle copied to clipboard
Add schedule config possibility from database
Are you open to a possibility to configure tasks (only the types that accept string arguments) using a database. I'm aware this can be created in my app, but having this out of the box would be a great addition to this nice package.
Interesting idea. My concern is with the added complexity. I'm also not sure how common such a requirement is... Are you thinking to use Doctrine ORM?
In my app, I have the task results stored in the db (which was easy to achieve) but not the definitions themselves.
I am completely open to an added event example showing how to achieve what you want. This would better scope the feature too - I've added some of the extending examples as features.
An example scheduler bundle that uses this is https://github.com/j-guyon/CommandSchedulerBundle. One of the things I like about this construction is that it allows to enable/disable command runs and configure cron times from a GUI. I think it could be in a separate package though.
What fields would we add to the Entity? Cron string for sure I think (maybe not if the user wants complete control) but what about the other properties/extensions?
I could see adding a basic base entity and subscriber:
abstract class ScheduledTask
{
abstract public function createTask(): Task // customize to your spec
public function isEnabled(): bool
{
return true; // override with your own logic
}
}
class DoctrineScheduledTaskSubscriber implements EventSubscriberInterface
{
public function __construct(
private ObjectManager $om,
private string $class, // your app's ScheduledTask class-string (from config)
) {}
public static function getSubscribedEvents(): array
{
return [BuildScheduleEvent::class => 'configureTasks'];
}
public function configureTasks(BuildScheduleEvent $event): void
{
foreach ($this->om->getRepository($this->class) as $entity) {
if (!$entity->isEnabled()) {
continue;
}
$event->getSchedule()->add($entity->createTask());
}
}
}
I thought more in a fully automated way.
The entity would not need a createTask
.
class DoctrineScheduledTaskSubscriber implements EventSubscriberInterface
{
/**
* @param class-string $class
*/
public function __construct(
private ObjectManager $om,
private string $class = \Zenstruck\ScheduleBundle\Entity\ScheduledCommandTask::class
) {}
public static function getSubscribedEvents(): array
{
return [BuildScheduleEvent::class => 'configureTasks'];
}
public function configureTasks(BuildScheduleEvent $event): void
{
foreach ($this->om->getRepository($this->class)->findEnabled() as $scheduledCommandTask) {
$event->getSchedule()
->addCommand($scheduledCommandTask->getCommand())
->description($scheduledCommandTask->getDescription())
// ...
->cron($scheduledCommandTask->getCronExpression());
}
}
}
I think most entity properties of https://github.com/j-guyon/CommandSchedulerBundle are usable, so I would add:
- (id)
- description
- command
- arguments
- cronExpression
- lastExecutedAt
- lastReturnCode
- disabled
- locked
After having played around with this some time I would add the following properties to the entity:
- (id)
- description
- command
- arguments
- expression
- lastRunAt (RunContext.startTime)
- lastResult (Result.type)
- lastResultMessage (Result.description)
- disabled
- locked
What's the difference between locked and disabled?
What about lastDuration and lastMemoryUsage?
Here's sort of what I'm thinking (for task definitions from db):
-
Model\TaskDefinition
interface with methodcreateTask(): Task
. -
Model\TaskDefinitionRepository
interface with methodfindTaskDefinitions(): array<TaskDefinition>
. - Abstract (MappedSuperclass)
Model\BaseTaskDefinition
with the implementation you describe above. - Concrete
Model\ORMTaskDefinitionRepository
with an ORM-specific implementation. -
DoctrineTaskDefinitionSubscriber
similar to above. This would use the repository to load tasks and add them to the schedule.
I think (1) and (2) above are important as it allows someone to do something custom.
This leaves adding the result to the task definition. Maybe TaskDefinitionRepository
has a handleResult(Result $result): void
method that a subscriber sends every result to it. It would be up to the definition to match with a db task definition and save. ORMTaskDefinitionRepository
could provide this implementation for BaseTaskDefinition
.
How are you planning to match up task results to task definitions?
What's the difference between locked and disabled?
Locked is a system state, disabled can be set by an admin interface for example.
What about lastDuration and lastMemoryUsage?
Good one, should be added...
hello @kbond and @gisostallenberg ,
Do you have any working example on how to implement Tasks managment via database like out of the box?
Thanks
Do you have any working example on how to implement Tasks managment via database like out of the box?
I don't, no. I'd suggest looking into symfony/scheduler
if you can. I know it has this ability but the docs are still a work in progress.
I'm sort of keeping this bundle in maintenance mode until Symfony 5.4 is EOL.
No, I'm sorry
Thank you. symfony/scheduler is the way for new projects