Skip to content

Commit

Permalink
API Update API to reflect changes in CLI interaction (#93)
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli authored Sep 26, 2024
1 parent 31d7270 commit 32d3f4f
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 232 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ class TestCron implements CronTask
}
```

Run `vendor/bin/sake dev/build flush=1` to make Silverstripe aware of the new
Run `vendor/bin/sake db:build --flush` to make Silverstripe aware of the new
module.

Then execute the crontask controller, it's preferable you do this via the CLI
since that is how the server will execute it.

```
vendor/bin/sake dev/cron
vendor/bin/sake cron-task
```

Server configuration
Expand All @@ -96,7 +96,7 @@ most common way is by adding a file to the `/etc/cron.d/` directory.
First find the correct command to execute, for example:

```
/usr/bin/php /path/to/silverstripe/docroot/vendor/bin/sake dev/cron
/usr/bin/php /path/to/silverstripe/docroot/vendor/bin/sake cron-task
```

Then find out which user the webserver is running on, for example `www-data`.
Expand All @@ -110,7 +110,7 @@ sudo vim /etc/cron.d/silverstripe-crontask
The content of that file should be:

```
* * * * * www-data /usr/bin/php /path/to/silverstripe/docroot/vendor/bin/sake dev/cron
* * * * * www-data /usr/bin/php /path/to/silverstripe/docroot/vendor/bin/sake cron-task
```

This will run every minute as the www-data user and check if there are any
Expand All @@ -122,7 +122,7 @@ adding quiet=1 - for example

```
[email protected]
* * * * * www-data /usr/bin/php /path/to/silverstripe/docroot/framework/cli-script.php dev/cron quiet=1
* * * * * www-data /usr/bin/php /path/to/silverstripe/docroot/vendor/bin/sake cron-task --quiet
```

**Warning**: Observe that the crontask module doesn't do any checking. If
Expand Down
13 changes: 3 additions & 10 deletions _config/crontask.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
---
Name: crontask
---
SilverStripe\Dev\DevelopmentAdmin:
registered_controllers:
cron:
controller: SilverStripe\CronTask\Controllers\CronTaskController
links:
cron: 'Run registered SilverStripe cron tasks'

SilverStripe\Control\Director:
rules:
'dev/cron/$Action': SilverStripe\CronTask\Controllers\CronTaskController
SilverStripe\Cli\Sake:
commands:
cron-task: 'SilverStripe\CronTask\Cli\CronTaskCommand'
117 changes: 117 additions & 0 deletions src/Cli/CronTaskCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<?php

namespace SilverStripe\CronTask\Cli;

use Cron\CronExpression;
use DateTime;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\CronTask\CronTaskStatus;
use SilverStripe\CronTask\Interfaces\CronTask;
use SilverStripe\ORM\FieldType\DBDatetime;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
* This command finds, checks and processes all crontasks
* Hidden because there's no reason to run this manually other than for debugging
*/
#[AsCommand('cron-task', 'Runs cron tasks that are scheduled to be run', aliases: ['dev/cron'], hidden: true)]
class CronTaskCommand extends Command
{
/**
* Determine if a task should be run
*/
public function isTaskDue(CronTask $task, CronExpression $cron): bool
{
// Get last run status
$status = CronTaskStatus::get_status(get_class($task));

// If the cron is due immediately, then run it
$now = new DateTime(DBDatetime::now()->getValue());
if ($cron->isDue($now)) {
if (empty($status) || empty($status->LastRun)) {
return true;
}
// In case this process is invoked twice in one minute, supress subsequent executions
$lastRun = new DateTime($status->LastRun);
return $lastRun->format('Y-m-d H:i') != $now->format('Y-m-d H:i');
}

// If this is the first time this task is ever checked, no way to detect postponed execution
if (empty($status) || empty($status->LastChecked)) {
return false;
}

// Determine if we have passed the last expected run time
$nextExpectedDate = $cron->getNextRunDate($status->LastChecked);
return $nextExpectedDate <= $now;
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
// Check each task
$tasks = ClassInfo::implementorsOf(CronTask::class);
if (empty($tasks)) {
$this->output(
_t(
CronTaskCommand::class . '.NO_IMPLEMENTERS',
'There are no implementators of CronTask to run'
),
$output
);
return Command::SUCCESS;
}
foreach ($tasks as $subclass) {
$task = Injector::inst()->create($subclass);
// falsey schedule = don't run task
if ($task->getSchedule()) {
$this->runTask($task, $output);
}
}
return Command::SUCCESS;
}

/**
* Checks and runs a single CronTask
*/
public function runTask(CronTask $task, OutputInterface $output): void
{
$cron = CronExpression::factory($task->getSchedule());
$isDue = $this->isTaskDue($task, $cron);
// Update status of this task prior to execution in case of interruption
CronTaskStatus::update_status(get_class($task), $isDue);
if ($isDue) {
$this->output(
_t(
CronTaskCommand::class . '.WILL_START_NOW',
'{task} will start now.',
['task' => get_class($task)]
),
$output
);
$task->process();
} else {
$this->output(
_t(
CronTaskCommand::class . '.WILL_RUN_AT',
'{task} will run at {time}.',
['task' => get_class($task), 'time' => $cron->getNextRunDate()->format('Y-m-d H:i:s')]
),
$output,
OutputInterface::VERBOSITY_VERBOSE
);
}
}

/**
* Output a message including the timestamp
*/
public function output(string $message, OutputInterface $output, int $verbosity = 0): void
{
$timestamp = DBDatetime::now()->Rfc2822();
$output->writeln($timestamp . ' - ' . $message, $verbosity);
}
}
192 changes: 0 additions & 192 deletions src/Controllers/CronTaskController.php

This file was deleted.

4 changes: 2 additions & 2 deletions src/Interfaces/CronTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
namespace SilverStripe\CronTask\Interfaces;

/**
* By implementing this interface a /dev/cron will be able to start in on the
* expression that you return frmo getSchedule();
* By implementing this interface `sake cron-task` will be able to start in on the
* expression that you return from getSchedule();
*
* @package crontask
*/
Expand Down
Loading

0 comments on commit 32d3f4f

Please sign in to comment.