Skip to content

Commit

Permalink
API Update API to reflect changes to CLI interaction
Browse files Browse the repository at this point in the history
  • Loading branch information
GuySartorelli committed Sep 6, 2024
1 parent feedb5f commit dde7a1e
Show file tree
Hide file tree
Showing 14 changed files with 283 additions and 238 deletions.
6 changes: 6 additions & 0 deletions _config/cli.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
Name: queuedjobs-cli
---
SilverStripe\Cli\Sake:
commands:
- 'Symbiote\QueuedJobs\Cli\ProcessJobQueueChildCommand'
7 changes: 3 additions & 4 deletions _config/taskrunner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ After:
- DevelopmentAdmin
---
SilverStripe\Dev\DevelopmentAdmin:
registered_controllers:
controllers:
tasks:
controller: Symbiote\QueuedJobs\Controllers\QueuedTaskRunner
links:
tasks: 'See a list of build tasks to run (QueuedJobs version)'
class: Symbiote\QueuedJobs\Controllers\QueuedTaskRunner
description: 'See a list of build tasks to run (QueuedJobs version)'
38 changes: 38 additions & 0 deletions src/Cli/ProcessJobQueueChildCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace Symbiote\QueuedJobs\Cli;

use Symbiote\QueuedJobs\Services\QueuedJobService;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand('queuedjobs:process-queue-child', hidden: true)]
class ProcessJobQueueChildCommand extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$task = @unserialize(@base64_decode($input->getArgument('base64-task')));
if ($task) {
$this->getService()->runJob($task->getDescriptor()->ID);
}
return Command::SUCCESS;
}

/**
* Returns an instance of the QueuedJobService.
*
* @return QueuedJobService
*/
protected function getService()
{
return QueuedJobService::singleton();
}

protected function configure()
{
$this->addArgument('base64-task', InputArgument::REQUIRED);
}
}
42 changes: 12 additions & 30 deletions src/Controllers/QueuedTaskRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
use Symbiote\QueuedJobs\Services\QueuedJobService;
use Symbiote\QueuedJobs\Tasks\CreateQueuedJobTask;
use Symbiote\QueuedJobs\Tasks\DeleteAllJobsTask;
use Symbiote\QueuedJobs\Tasks\ProcessJobQueueChildTask;
use Symbiote\QueuedJobs\Tasks\ProcessJobQueueTask;

/**
Expand All @@ -29,55 +28,34 @@
*/
class QueuedTaskRunner extends TaskRunner
{
/**
* @var array
*/
private static $url_handlers = [
private static array $url_handlers = [
'queue/$TaskName' => 'queueTask',
];

/**
* @var array
*/
private static $allowed_actions = [
private static array $allowed_actions = [
'queueTask',
];

/**
* @var array
*/
private static $css = [
private static array $css = [
'symbiote/silverstripe-queuedjobs:client/styles/task-runner.css',
];

/**
* Tasks on this list will be available to be run only via browser
*
* @config
* @var array
* Tasks on this list will not be available to run via the jobs queue
*/
private static $task_blacklist = [
private static array $task_blacklist = [
ProcessJobQueueTask::class,
ProcessJobQueueChildTask::class,
CreateQueuedJobTask::class,
DeleteAllJobsTask::class,
];

/**
* Tasks on this list will be available to be run only via jobs queue
*
* @config
* @var array
*/
private static $queued_only_tasks = [];
private static array $queued_only_tasks = [];

public function index()
{
if (Director::is_cli()) {
// CLI mode - revert to default behaviour
return parent::index();
}

$baseUrl = Director::absoluteBaseURL();
$tasks = $this->getTasks();

Expand Down Expand Up @@ -108,6 +86,8 @@ public function index()
'Title' => $task['title'],
'Description' => $task['description'],
'Type' => 'universal',
'Parameters' => $task['parameters'],
'Help' => $task['help'],
]));
}

Expand All @@ -118,18 +98,20 @@ public function index()
'Title' => $task['title'],
'Description' => $task['description'],
'Type' => 'immediate',
'Parameters' => $task['parameters'],
'Help' => $task['help'],
]));
}

// Queue only tasks
$queueOnlyTaskList = ArrayList::create();

foreach ($queuedOnlyTasks as $task) {
$taskList->push(ArrayData::create([
'QueueLink' => Controller::join_links($baseUrl, 'dev/tasks/queue', $task['segment']),
'Title' => $task['title'],
'Description' => $task['description'],
'Type' => 'queue-only',
'Parameters' => $task['parameters'],
'Help' => $task['help'],
]));
}

Expand Down
8 changes: 6 additions & 2 deletions src/Jobs/RunBuildTaskJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\BuildTask;
use SilverStripe\HybridExecution\HybridOutput;
use SilverStripe\ORM\DataObject;
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJob;
use Symfony\Component\Console\Input\ArrayInput;

/**
* A convenience wrapper for running BuildTask implementations.
Expand Down Expand Up @@ -83,8 +85,10 @@ public function process()

$getVars = [];
parse_str($this->QueryString ?? '', $getVars);
$request = new HTTPRequest('GET', '/', $getVars);
$task->run($request);
$output = HybridOutput::create(HybridOutput::FORMAT_ANSI);
$input = new ArrayInput($getVars);
$input->setInteractive(false);
$task->run($input, $output);

$this->currentStep = 1;
$this->isComplete = true;
Expand Down
26 changes: 26 additions & 0 deletions src/Services/AbstractQueuedJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,30 @@ public function __get($name)
{
return isset($this->jobData->$name) ? $this->jobData->$name : null;
}

/**
* Resolves a queue name to one of the queue constants.
* If $queue is already an int representing a queue, that int will be returned.
* If the queue is unknown, `null` will be returned.
*/
public static function getQueue(string|int $queue): ?int
{
switch (strtolower($queue)) {
case 'immediate':
$queue = QueuedJob::IMMEDIATE;
break;
case 'queued':
$queue = QueuedJob::QUEUED;
break;
case 'large':
$queue = QueuedJob::LARGE;
break;
default:
$queues = [QueuedJob::IMMEDIATE, QueuedJob::QUEUED, QueuedJob::LARGE];
if (!ctype_digit($queue) || !in_array((int) $queue, $queues)) {
return null;
}
}
return $queue;
}
}
61 changes: 38 additions & 23 deletions src/Tasks/CheckJobHealthTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,21 @@

namespace Symbiote\QueuedJobs\Tasks;

use Exception;
use SilverStripe\Control\HTTPRequest;
use Composer\Console\Input\InputOption;
use Psr\Log\LoggerInterface;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\BuildTask;
use Symbiote\QueuedJobs\Services\QueuedJob;
use SilverStripe\HybridExecution\HybridOutput;
use Symbiote\QueuedJobs\Services\AbstractQueuedJob;
use Symbiote\QueuedJobs\Services\QueuedJobService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;

class CheckJobHealthTask extends BuildTask
{
/**
* {@inheritDoc}
* @var string
*/
private static $segment = 'CheckJobHealthTask';
protected static string $commandName = 'CheckJobHealthTask';

/**
* {@inheritDoc}
* @return string
*/
public function getDescription()
public static function getDescription(): string
{
return _t(
__CLASS__ . '.Description',
Expand All @@ -32,30 +28,49 @@ public function getDescription()
/**
* Implement this method in the task subclass to
* execute via the TaskRunner
*
* @param HTTPRequest $request
* @return
*
* @throws Exception
*/
public function run($request)
protected function execute(InputInterface $input, HybridOutput $output): int
{
$queue = $request->requestVar('queue') ?: QueuedJob::QUEUED;
$queue = AbstractQueuedJob::getQueue($input->getOption('queue'));
if ($queue === null) {
$output->writeln('<error>queue must be one of "immediate", "queued", or "large"</>');
return Command::INVALID;
}
$jobHealth = $this->getService()->checkJobHealth($queue);

$unhealthyJobCount = 0;

foreach ($jobHealth as $type => $IDs) {
$count = count($IDs ?? []);
echo 'Detected and attempted restart on ' . $count . ' ' . $type . ' jobs';
$output->writeln('Detected and attempted restart on ' . $count . ' ' . $type . ' jobs');
$unhealthyJobCount = $unhealthyJobCount + $count;
}

if ($unhealthyJobCount > 0) {
throw new Exception("$unhealthyJobCount jobs are unhealthy");
$msg = "$unhealthyJobCount jobs are unhealthy";
/** @var LoggerInterface $logger */
$Logger = Injector::inst()->get(LoggerInterface::class . '.errorhandler');
$Logger->error($msg);
$output->writeln($msg);
return Command::FAILURE;
}

echo 'All jobs are healthy';
$output->writeln('All jobs are healthy');
return Command::SUCCESS;
}

public function getOptions(): array
{
return [
new InputOption(
'queue',
null,
InputOption::VALUE_REQUIRED,
'The queue to check',
'queued',
['immediate', 'queued', 'large']
),
];
}

protected function getService()
Expand Down
Loading

0 comments on commit dde7a1e

Please sign in to comment.