Skip to content

Commit

Permalink
Added 'outdated' option to scheduler command (#3771)
Browse files Browse the repository at this point in the history
  • Loading branch information
maelanleborgne authored Jan 5, 2024
1 parent 88eb9f9 commit a71403f
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 2 deletions.
22 changes: 22 additions & 0 deletions system/src/Grav/Common/Scheduler/Job.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,28 @@ public function isDue(DateTime $date = null)
return $this->executionTime->isDue($date);
}

/**
* Check if the Job should have run previously.
*
* @param DateTime|null $date
* @return bool
*/
public function isOverdue(?DateTime $date = null, ?DateTime $lastRun = null)
{
// If the time elapsed since the creation is inferior to the interval, it's not overdue
if ($this->creationTime > $this->executionTime->getPreviousRunDate($date)) {
return false;
}
// Else, if the job has never run, it's overdue
if (null === $lastRun) {
return true;
}
$date = $date ?? new DateTime('now');

// Else if the last run time is inferior to the previous scheduled time, it's overdue
return $lastRun < $this->executionTime->getPreviousRunDate($date);
}

/**
* Check if the Job is overlapping.
*
Expand Down
12 changes: 10 additions & 2 deletions system/src/Grav/Common/Scheduler/Scheduler.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ public function addCommand($command, $args = [], $id = null)
* @param DateTime|null $runTime Optional, run at specific moment
* @param bool $force force run even if not due
*/
public function run(DateTime $runTime = null, $force = false)
public function run(DateTime $runTime = null, $force = false, $overdue = false)
{
$this->loadSavedJobs();

Expand All @@ -199,9 +199,17 @@ public function run(DateTime $runTime = null, $force = false)
$runTime = new DateTime('now');
}

if ($overdue) {
$lastRuns = [];
foreach ($this->getJobStates()->content() as $id => $state) {
$timestamp = $state['last-run'] ?? time();
$lastRuns[$id] = DateTime::createFromFormat('U',$timestamp);
}
}

// Star processing jobs
foreach ($alljobs as $job) {
if ($job->isDue($runTime) || $force) {
if ($job->isDue($runTime) || $force || ($overdue && $job->isOverdue($runTime, $lastRuns[$job->getId()] ?? null))) {
$job->run();
$this->jobs_run[] = $job;
}
Expand Down
82 changes: 82 additions & 0 deletions tests/unit/Grav/Common/Scheduler/JobTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace unit\Grav\Common\Scheduler;

use Grav\Common\Scheduler\Job;

class JobTest extends \Codeception\Test\Unit
{
/**
* @dataProvider dataProviderForTestIsOverdue
*/
public function testIsOverdue($job, $date, $lastRun, $expected)
{
$this->assertEquals($expected, $job->isOverdue($date, $lastRun));
}

public function dataProviderForTestIsOverdue()
{
return [
'New Job' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => null,
'lastRun' => null,
'expected' => false
],
'New Job created 1 hour ago' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => new \DateTime('+1 hour'),
'lastRun' => null,
'expected' => true
],
'New Job created 1 minute ago' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => new \DateTime('+1 minute'),
'lastRun' => null,
'expected' => false
],
'New Job created 2 minutes ago' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => new \DateTime('+2 minutes'),
'lastRun' => null,
'expected' => true
],
'Job created 1 hour ago and last run 1 mn ago' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => new \DateTime('+1 hour'),
'lastRun' => new \DateTime('+1 minutes'),
'expected' => true
],
'Job created 1 hour ago and last run 30 mn ago' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => new \DateTime('+1 hour'),
'lastRun' => new \DateTime('+30 minutes'),
'expected' => true
],
'Job created 30 minutes ago and last run 1 hour ago' => [
'job' => (new Job('ls'))->at('* * * * *'),
'date' => new \DateTime('+30 minutes'),
'lastRun' => new \DateTime('+1 hour'),
'expected' => false
],
'New hourly Job' => [
'job' => (new Job('ls'))->at('0 * * * *'),
'date' => null,
'lastRun' => null,
'expected' => false
],
'New hourly Job created at 2 hours ago' => [
'job' => (new Job('ls'))->at('0 * * * *'),
'date' => new \DateTime('+2 hours'),
'lastRun' => null,
'expected' => true
],
'Hourly Job created 1 hour ago and last run 30 mn ago' => [
'job' => (new Job('ls'))->at('0 * * * *'),
'date' => new \DateTime('+1 hour'),
'lastRun' => new \DateTime('+30 minutes'),
'expected' => true
],
];
}
}
80 changes: 80 additions & 0 deletions tests/unit/Grav/Common/Scheduler/SchedulerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

namespace unit\Grav\Common\Scheduler;

use Codeception\Util\Fixtures;
use Grav\Common\Grav;
use Grav\Common\Scheduler\Scheduler;
use Grav\Common\Yaml;
use RocketTheme\Toolbox\File\File;

class SchedulerTest extends \Codeception\Test\Unit
{
/**
* @var \UnitTester
*/
protected $tester;

protected $grav;

/**
* @var \Grav\Common\Scheduler\Scheduler
*/
protected $scheduler;
private $statusFilePath;

public function dataProviderForTestIsOverdue()
{
return [
[
new \DateTime('+2 hours'),
[
'aze45aze' => ['args'=>[], 'command'=>'ls', 'at'=>'0 * * * *'],
],
[
'aze45aze' => ['last-run' => strtotime('2021-01-01 00:00:00')],
]
],
[
new \DateTime('+2 hours'),
[
'aze45aze' => ['args'=>[], 'command'=>'ls', 'at'=>'0 * * * *'],
'zedz5a4eza' => ['args'=>[], 'command'=>'ls', 'at'=>'*/15 * * * *'],
],
[
'aze45aze' => ['last-run' => strtotime('-5 minutes')],
]
],
];
}

protected function _before()
{
$this->grav = Fixtures::get('grav')();
$this->scheduler = new Scheduler();
$this->statusFilePath = Grav::instance()['locator']->findResource('user-data://scheduler', true, true).'/status.yaml';
}

protected function _after()
{
if (file_exists($this->statusFilePath)) {
unlink($this->statusFilePath);
}
}

/**
* @dataProvider dataProviderForTestIsOverdue
*/
public function testIsOverdue($date, $jobs, $status){
$file = $this->scheduler->getJobStates();
$file->save($status);
$this->grav['config']->set('scheduler.custom_jobs', $jobs);
$this->scheduler->run($date, false, true);
$this->assertFileExists($this->statusFilePath);
$this->assertFileIsReadable($this->statusFilePath);
dump(file_get_contents($this->statusFilePath));
foreach ($jobs as $id => $job) {
$this->assertStringContainsString($id, file_get_contents($this->statusFilePath));
}
}
}

0 comments on commit a71403f

Please sign in to comment.