Files
chill-bundles/docs/source/development/cronjob.md

3.5 KiB

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".

Cron jobs

Some tasks must be executed regularly: refresh some materialized views, remove old data, ...

For this purpose, one can programmatically implements a "cron job", which will be scheduled by a specific command.

The command chill:cron-job:execute

The command chill:cron-job:execute will schedule a task, one by one. In a classical implementation, it should be executed every 15 minutes (more or less), to ensure that every task can be executed.

This command should not be executed in parallel. The installer should ensure that two job are executed concurrently.

How to implements a cron job ?

Implements a Chill\MainBundle\Cron\CronJobInterface. Here is an example:

namespace Chill\MainBundle\Service\Something;

use Chill\MainBundle\Cron\CronJobInterface;
use Chill\MainBundle\Entity\CronJobExecution;
use DateInterval;
use DateTimeImmutable;
use Symfony\Component\Clock\ClockInterface;

class MyCronJob implements CronJobInterface
{
    function __construct(private ClockInterface $clock) {}

    public function canRun(?CronJobExecution $cronJobExecution): bool
    {
        // the parameter $cronJobExecution contains data about the last execution of the cronjob
        // if it is null, it should be executed immediatly
        if (null === $cronJobExecution) {
            return true;
        }

        if ($cronJobExecution->getKey() !== $this->getKey()) {
            throw new UnexpectedValueException();
        }

        // this cron job should be executed if the last execution is greater than one day, but only during the night

        $now = $clock->now();

        return $cronJobExecution->getLastStart() < $now->sub(new DateInterval('P1D'))
            && in_array($now->format('H'), self::ACCEPTED_HOURS, true)
            // introduce a random component to ensure a roll of task execution when multiple instances are hosted on same machines
            && mt_rand(0, 5) === 0;
    }

    public function getKey(): string
    {
        return 'arbitrary-and-unique-key';
    }

    public function run(array $lastExecutionData): void
    {
        // here, we execute the command

        // we return execution data, which will be served for next execution
        // this data should be easily serializable in a json column: it should contains
        // only int, string, etc. Avoid storing object
        return ['last-execution-id' => 0];
   }
}

How are cron job scheduled ?

If the command chill:cron-job:execute is run with one or more job argument, those jobs are run, without checking that the job can run (the method canRun is not executed).

If any job argument is given, the CronManager schedule job with those steps:

  • the tasks are ordered, with:
    • a priority is given for tasks that weren't never executed;
    • then, the tasks are ordered, the last executed are the first in the list
  • then, for each tasks, and in the given order, the first task where canRun return TRUE will be executed.

The command chill:cron-job:execute execute only one task.