schedule-bundle icon indicating copy to clipboard operation
schedule-bundle copied to clipboard

Add schedule config possibility from database

Open gisostallenberg opened this issue 2 years ago • 12 comments

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.

gisostallenberg avatar Jul 20 '22 11:07 gisostallenberg

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.

kbond avatar Jul 20 '22 13:07 kbond

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.

gisostallenberg avatar Jul 20 '22 13:07 gisostallenberg

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());
        }
    }
}

kbond avatar Jul 20 '22 14:07 kbond

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

gisostallenberg avatar Jul 21 '22 09:07 gisostallenberg

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

gisostallenberg avatar Jul 22 '22 11:07 gisostallenberg

What's the difference between locked and disabled?

What about lastDuration and lastMemoryUsage?

kbond avatar Jul 22 '22 11:07 kbond

Here's sort of what I'm thinking (for task definitions from db):

  1. Model\TaskDefinition interface with method createTask(): Task.
  2. Model\TaskDefinitionRepository interface with method findTaskDefinitions(): array<TaskDefinition>.
  3. Abstract (MappedSuperclass) Model\BaseTaskDefinition with the implementation you describe above.
  4. Concrete Model\ORMTaskDefinitionRepository with an ORM-specific implementation.
  5. 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?

kbond avatar Jul 22 '22 12:07 kbond

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

gisostallenberg avatar Jul 27 '22 11:07 gisostallenberg

hello @kbond and @gisostallenberg ,

Do you have any working example on how to implement Tasks managment via database like out of the box?

Thanks

pribeirojtm avatar Jan 26 '24 14:01 pribeirojtm

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.

kbond avatar Jan 26 '24 14:01 kbond

No, I'm sorry

gisostallenberg avatar Feb 02 '24 12:02 gisostallenberg

Thank you. symfony/scheduler is the way for new projects

pribeirojtm avatar Feb 02 '24 14:02 pribeirojtm