Skip to content
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

[Draft] [Scheduler] Added 'outdated' option to scheduler command #3771

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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));
}
}
}