721 lines
24 KiB
PHP
721 lines
24 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* @file tools/jobs.php
|
|
*
|
|
* Copyright (c) 2014-2022 Simon Fraser University
|
|
* Copyright (c) 2003-2022 John Willinsky
|
|
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
|
|
*
|
|
* @class commandJobs
|
|
*
|
|
* @ingroup tools
|
|
*
|
|
* @brief CLI tool to list, iterate and purge queued jobs on database
|
|
*/
|
|
|
|
namespace PKP\tools;
|
|
|
|
use APP\core\Application;
|
|
use APP\facades\Repo;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Console\Concerns\InteractsWithIO;
|
|
use Illuminate\Console\OutputStyle;
|
|
use Illuminate\Contracts\Queue\Job;
|
|
use Illuminate\Http\Resources\Json\JsonResource;
|
|
use Illuminate\Queue\Events\JobFailed;
|
|
use Illuminate\Queue\Events\JobProcessed;
|
|
use Illuminate\Queue\Events\JobProcessing;
|
|
use PKP\cliTool\CommandLineTool;
|
|
use PKP\config\Config;
|
|
use PKP\job\models\Job as PKPJobModel;
|
|
use PKP\jobs\testJobs\TestJobFailure;
|
|
use PKP\jobs\testJobs\TestJobSuccess;
|
|
use PKP\queue\WorkerConfiguration;
|
|
use Symfony\Component\Console\Exception\CommandNotFoundException;
|
|
use Symfony\Component\Console\Exception\InvalidArgumentException as CommandInvalidArgumentException;
|
|
use Symfony\Component\Console\Helper\Helper;
|
|
use Symfony\Component\Console\Helper\TableCell;
|
|
use Symfony\Component\Console\Helper\TableCellStyle;
|
|
use Symfony\Component\Console\Input\StringInput;
|
|
use Symfony\Component\Console\Output\StreamOutput;
|
|
use Throwable;
|
|
|
|
define('APP_ROOT', dirname(__FILE__, 4));
|
|
require_once APP_ROOT . '/tools/bootstrap.php';
|
|
|
|
class commandInterface
|
|
{
|
|
use InteractsWithIO;
|
|
|
|
public function __construct()
|
|
{
|
|
$output = new OutputStyle(
|
|
new StringInput(''),
|
|
new StreamOutput(fopen('php://stdout', 'w'))
|
|
);
|
|
|
|
$this->setOutput($output);
|
|
}
|
|
|
|
public function errorBlock(array $messages = [], ?string $title = null): void
|
|
{
|
|
$this->getOutput()->block(
|
|
$messages,
|
|
$title,
|
|
'fg=white;bg=red',
|
|
' ',
|
|
true
|
|
);
|
|
}
|
|
}
|
|
|
|
class commandJobs extends CommandLineTool
|
|
{
|
|
protected const AVAILABLE_OPTIONS = [
|
|
'list' => 'admin.cli.tool.jobs.available.options.list.description',
|
|
'purge' => 'admin.cli.tool.jobs.available.options.purge.description',
|
|
'test' => 'admin.cli.tool.jobs.available.options.test.description',
|
|
'total' => 'admin.cli.tool.jobs.available.options.total.description',
|
|
'help' => 'admin.cli.tool.jobs.available.options.help.description',
|
|
'run' => 'admin.cli.tool.jobs.available.options.run.description',
|
|
'work' => 'admin.cli.tool.jobs.available.options.work.description',
|
|
'failed' => 'admin.cli.tool.jobs.available.options.failed.description',
|
|
'restart' => 'admin.cli.tool.jobs.available.options.restart.description',
|
|
'usage' => 'admin.cli.tool.jobs.available.options.usage.description',
|
|
];
|
|
|
|
protected const CURRENT_PAGE = 'current';
|
|
protected const PREVIOUS_PAGE = 'previous';
|
|
protected const NEXT_PAGE = 'next';
|
|
|
|
/**
|
|
* @var null|string Which option will be call?
|
|
*/
|
|
protected $option = null;
|
|
|
|
/**
|
|
* @var null|array Parameters and arguments from CLI
|
|
*/
|
|
protected $parameterList = null;
|
|
|
|
/**
|
|
* CLI interface, this object should extends InteractsWithIO
|
|
*/
|
|
protected $commandInterface = null;
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct($argv = [])
|
|
{
|
|
parent::__construct($argv);
|
|
|
|
array_shift($argv);
|
|
|
|
$this->setParameterList($argv);
|
|
|
|
if (!isset($this->getParameterList()[0])) {
|
|
throw new CommandNotFoundException(
|
|
__('admin.cli.tool.jobs.empty.option'),
|
|
array_keys(self::AVAILABLE_OPTIONS)
|
|
);
|
|
}
|
|
|
|
$this->option = $this->getParameterList()[0];
|
|
|
|
$this->setCommandInterface(new commandInterface());
|
|
}
|
|
|
|
public function setCommandInterface(commandInterface $commandInterface): self
|
|
{
|
|
$this->commandInterface = $commandInterface;
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function getCommandInterface(): commandInterface
|
|
{
|
|
return $this->commandInterface;
|
|
}
|
|
|
|
/**
|
|
* Save the parameter list passed on CLI
|
|
*
|
|
* @param array $items Array with parameters and arguments passed on CLI
|
|
*
|
|
*/
|
|
public function setParameterList(array $items): self
|
|
{
|
|
$parameters = [];
|
|
|
|
foreach ($items as $param) {
|
|
if (strpos($param, '=')) {
|
|
[$key, $value] = explode('=', ltrim($param, '-'));
|
|
$parameters[$key] = $value;
|
|
|
|
continue;
|
|
}
|
|
|
|
$parameters[] = $param;
|
|
}
|
|
|
|
$this->parameterList = $parameters;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get the parameter list passed on CLI
|
|
*
|
|
*/
|
|
public function getParameterList(): ?array
|
|
{
|
|
return $this->parameterList;
|
|
}
|
|
|
|
/**
|
|
* Get the value of a specific parameter
|
|
*
|
|
* @param mixed $default
|
|
*
|
|
*/
|
|
protected function getParameterValue(string $parameter, mixed $default = null): mixed
|
|
{
|
|
if (!isset($this->getParameterList()[$parameter])) {
|
|
return $default;
|
|
}
|
|
|
|
return $this->getParameterList()[$parameter];
|
|
}
|
|
|
|
/**
|
|
* Print command usage information.
|
|
*/
|
|
public function usage()
|
|
{
|
|
$this->getCommandInterface()->line('<comment>' . __('admin.cli.tool.usage.title') . '</comment>');
|
|
$this->getCommandInterface()->line(__('admin.cli.tool.usage.parameters') . PHP_EOL);
|
|
$this->getCommandInterface()->line('<comment>' . __('admin.cli.tool.available.commands', ['namespace' => 'jobs']) . '</comment>');
|
|
|
|
$this->printUsage(self::AVAILABLE_OPTIONS);
|
|
}
|
|
|
|
/**
|
|
* Alias for usage command
|
|
*/
|
|
public function help(): void
|
|
{
|
|
$this->usage();
|
|
}
|
|
|
|
/**
|
|
* Retrieve the columnWidth based on the commands text size
|
|
*/
|
|
protected function getColumnWidth(array $commands): int
|
|
{
|
|
$widths = [];
|
|
|
|
foreach ($commands as $command) {
|
|
$widths[] = Helper::width($command);
|
|
}
|
|
|
|
return $widths ? max($widths) + 2 : 0;
|
|
}
|
|
|
|
/**
|
|
* Failed jobs list/redispatch/remove
|
|
*/
|
|
protected function failed(): void
|
|
{
|
|
$parameterList = $this->getParameterList();
|
|
|
|
if (in_array('--redispatch', $parameterList) || ($jobIds = $this->getParameterValue('redispatch'))) {
|
|
$jobsCount = Repo::failedJob()->redispatchToQueue(
|
|
$this->getParameterValue('queue'),
|
|
collect(explode(',', $jobIds ?? ''))
|
|
->filter()
|
|
->map(fn ($item) => (int)$item)
|
|
->toArray()
|
|
);
|
|
$this->getCommandInterface()->getOutput()->success(__('admin.cli.tool.jobs.failed.redispatch.successful', ['jobsCount' => $jobsCount]));
|
|
return;
|
|
}
|
|
|
|
if (in_array('--clear', $parameterList) || ($jobIds = $this->getParameterValue('clear'))) {
|
|
$jobsCount = Repo::failedJob()->deleteJobs(
|
|
$this->getParameterValue('queue'),
|
|
collect(explode(',', $jobIds ?? ''))
|
|
->filter()
|
|
->map(fn ($item) => (int)$item)
|
|
->toArray()
|
|
);
|
|
$this->getCommandInterface()->getOutput()->success(__('admin.cli.tool.jobs.failed.clear.successful', ['jobsCount' => $jobsCount]));
|
|
return;
|
|
}
|
|
|
|
array_push($this->parameterList, '--failed');
|
|
|
|
$this->list();
|
|
}
|
|
|
|
/**
|
|
* Signal the queue worker to quit gracefully
|
|
*/
|
|
protected function restart(): void
|
|
{
|
|
$cache = app()->get("cache.store"); /** @var \Illuminate\Contracts\Cache\Repository $cache */
|
|
|
|
$cache->forever('illuminate:queue:restart', Carbon::now()->getTimestamp());
|
|
|
|
$this
|
|
->getCommandInterface()
|
|
->getOutput()
|
|
->info(__('admin.cli.tool.jobs.available.options.restart.confirm'));
|
|
}
|
|
|
|
/**
|
|
* List all queued jobs
|
|
*/
|
|
protected function list(): void
|
|
{
|
|
$perPage = $this->getParameterValue('perPage', '10');
|
|
$page = $this->getParameterValue('page', '1');
|
|
|
|
$parameterList = $this->getparameterList();
|
|
|
|
$repository = in_array('--failed', $parameterList) ? Repo::failedJob() : Repo::job();
|
|
|
|
$data = $repository
|
|
->setOutputFormat($repository::OUTPUT_CLI)
|
|
->perPage((int) $perPage)
|
|
->setPage((int) $page)
|
|
->showJobs();
|
|
|
|
$this->total();
|
|
|
|
$this->getCommandInterface()->table(
|
|
$this->getListTableFormat(),
|
|
$data
|
|
->map(fn(JsonResource $job) => $job->toArray(app('request')))
|
|
->toArray()
|
|
);
|
|
|
|
$pagination = [
|
|
'pagination' => [
|
|
self::CURRENT_PAGE => $data->currentPage(),
|
|
self::PREVIOUS_PAGE => ($data->currentPage() - 1) > 0 ? $data->currentPage() - 1 : 1,
|
|
self::NEXT_PAGE => $data->currentPage(),
|
|
],
|
|
];
|
|
|
|
if ($data->hasMorePages()) {
|
|
$pagination['pagination'][self::NEXT_PAGE] = $data->currentPage() + 1;
|
|
}
|
|
|
|
$this->getCommandInterface()
|
|
->table(
|
|
[
|
|
[
|
|
new TableCell(
|
|
__('admin.cli.tool.jobs.pagination'),
|
|
[
|
|
'colspan' => 3,
|
|
'style' => new TableCellStyle(['align' => 'center'])
|
|
]
|
|
)
|
|
],
|
|
[
|
|
__('admin.cli.tool.jobs.pagination.current'),
|
|
__('admin.cli.tool.jobs.pagination.previous'),
|
|
__('admin.cli.tool.jobs.pagination.next'),
|
|
]
|
|
],
|
|
$pagination
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get table format for list view
|
|
*/
|
|
protected function getListTableFormat(): array
|
|
{
|
|
$listForFailedJobs = in_array('--failed', $this->getParameterList());
|
|
|
|
return [
|
|
[
|
|
new TableCell(
|
|
$listForFailedJobs
|
|
? __('admin.cli.tool.jobs.queued.jobs.failed.title')
|
|
: __('admin.cli.tool.jobs.queued.jobs.title'),
|
|
[
|
|
'colspan' => $listForFailedJobs ? 6 : 7,
|
|
'style' => new TableCellStyle(['align' => 'center'])
|
|
]
|
|
)
|
|
],
|
|
array_merge([
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.id'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.queue'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.job.display.name'),
|
|
], $listForFailedJobs ? [
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.connection'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.failed.at'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.exception'),
|
|
] : [
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.attempts'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.reserved.at'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.available.at'),
|
|
__('admin.cli.tool.jobs.queued.jobs.fields.created.at')
|
|
])
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Run daemon worker process to continue handle jobs
|
|
*/
|
|
protected function work(): void
|
|
{
|
|
$parameterList = $this->getParameterList();
|
|
|
|
if (in_array('--help', $parameterList)) {
|
|
$this->workerOptionsHelp();
|
|
return;
|
|
}
|
|
|
|
if (Application::isUnderMaintenance()) {
|
|
$this->getCommandInterface()->getOutput()->error(__('admin.cli.tool.jobs.maintenance.message'));
|
|
return;
|
|
}
|
|
|
|
if (Config::getVar('general', 'sandbox', false)) {
|
|
$this->getCommandInterface()->getOutput()->error(__('admin.cli.tool.jobs.sandbox.message'));
|
|
error_log(__('admin.cli.tool.jobs.sandbox.message'));
|
|
return;
|
|
}
|
|
|
|
$connection = $parameterList['connection'] ?? Config::getVar('queues', 'default_connection', 'database');
|
|
$queue = $parameterList['queue'] ?? Config::getVar('queues', 'default_queue', 'queue');
|
|
|
|
if (in_array('--test', $parameterList)) {
|
|
$queue = PKPJobModel::TESTING_QUEUE;
|
|
}
|
|
|
|
$this->listenForEvents();
|
|
|
|
app('pkpJobQueue')->runJobsViaDaemon(
|
|
$connection,
|
|
$queue,
|
|
$this->gatherWorkerOptions($parameterList)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Dispatch jobs into the queue
|
|
*/
|
|
protected function run(): void
|
|
{
|
|
if (Application::isUnderMaintenance()) {
|
|
$this->getCommandInterface()->getOutput()->error(__('admin.cli.tool.jobs.maintenance.message'));
|
|
return;
|
|
}
|
|
|
|
if (Config::getVar('general', 'sandbox', false)) {
|
|
$this->getCommandInterface()->getOutput()->error(__('admin.cli.tool.jobs.sandbox.message'));
|
|
error_log(__('admin.cli.tool.jobs.sandbox.message'));
|
|
return;
|
|
}
|
|
|
|
$parameterList = $this->getParameterList();
|
|
|
|
$queue = $parameterList['queue'] ?? Config::getVar('queues', 'default_queue', 'queue');
|
|
|
|
if (in_array('--test', $parameterList)) {
|
|
$queue = PKPJobModel::TESTING_QUEUE;
|
|
}
|
|
|
|
$jobQueue = app('pkpJobQueue');
|
|
|
|
if ($queue && is_string($queue)) {
|
|
$jobQueue = $jobQueue->forQueue($queue);
|
|
}
|
|
|
|
$jobBuilder = $jobQueue->getJobModelBuilder();
|
|
|
|
if (($jobCount = $jobBuilder->count()) <= 0) {
|
|
$this->getCommandInterface()->getOutput()->info(
|
|
__(
|
|
'admin.cli.tool.jobs.available.options.run.empty.description',
|
|
['queueName' => $queue,]
|
|
)
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
$this->listenForEvents();
|
|
|
|
while ($jobBuilder->count()) {
|
|
$jobQueue->runJobInQueue();
|
|
|
|
if (in_array('--once', $parameterList)) {
|
|
$jobCount = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$this->getCommandInterface()->getOutput()->success(
|
|
__(
|
|
'admin.cli.tool.jobs.available.options.run.completed.description',
|
|
['jobCount' => $jobCount, 'queueName' => $queue,]
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Purge queued jobs
|
|
*/
|
|
protected function purge(): void
|
|
{
|
|
if (!isset($this->getParameterList()['queue']) && !isset($this->getParameterList()[1])) {
|
|
throw new CommandInvalidArgumentException(__('admin.cli.tool.jobs.purge.without.id'));
|
|
}
|
|
|
|
$parameterList = $this->getParameterList();
|
|
|
|
if (in_array('--all', $parameterList) || ($queue = $this->getParameterValue('queue'))) {
|
|
if (!Repo::job()->deleteJobs($queue ?? null)) {
|
|
$this->getCommandInterface()->getOutput()->warning(__('admin.cli.tool.jobs.purge.impossible.to.purge.empty'));
|
|
return;
|
|
}
|
|
|
|
$this->getCommandInterface()->getOutput()->success(__('admin.cli.tool.jobs.purge.successful.all'));
|
|
return;
|
|
}
|
|
|
|
$deleted = Repo::job()->delete((int) $this->getParameterList()[1]);
|
|
|
|
if (!$deleted) {
|
|
throw new CommandInvalidArgumentException(__('admin.cli.tool.jobs.purge.invalid.id'));
|
|
}
|
|
|
|
$this->getCommandInterface()->getOutput()->success(__('admin.cli.tool.jobs.purge.successful'));
|
|
}
|
|
|
|
/**
|
|
* Create a test queued job
|
|
*/
|
|
protected function test(): void
|
|
{
|
|
$queue = PKPJobModel::TESTING_QUEUE;
|
|
$runnableJob = $this->getParameterList()['only'] ?? null;
|
|
|
|
if ($runnableJob && !in_array($runnableJob, ['failed', 'success'])) {
|
|
throw new CommandInvalidArgumentException(__('admin.cli.tool.jobs.test.invalid.option'));
|
|
}
|
|
|
|
if (!$runnableJob || $runnableJob === 'failed') {
|
|
dispatch(new TestJobFailure());
|
|
|
|
$this->getCommandInterface()->getOutput()->success(__('admin.cli.tool.jobs.test.job.failed.dispatch.message', ['queueName' => $queue]));
|
|
}
|
|
|
|
if (!$runnableJob || $runnableJob === 'success') {
|
|
dispatch(new TestJobSuccess());
|
|
|
|
$this->getCommandInterface()->getOutput()->success(__('admin.cli.tool.jobs.test.job.success.dispatch.message', ['queueName' => $queue]));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gather worker daemon options
|
|
*
|
|
*/
|
|
protected function gatherWorkerOptions(array $parameters = []): array
|
|
{
|
|
$workerConfig = new WorkerConfiguration();
|
|
|
|
return [
|
|
'name' => $this->getParameterValue('name', $workerConfig->getName()),
|
|
'backoff' => $this->getParameterValue('backoff', $workerConfig->getBackoff()),
|
|
'memory' => $this->getParameterValue('memory', $workerConfig->getMemory()),
|
|
'timeout' => $this->getParameterValue('timeout', $workerConfig->getTimeout()),
|
|
'sleep' => $this->getParameterValue('sleep', $workerConfig->getSleep()),
|
|
'maxTries' => $this->getParameterValue('tries', $workerConfig->getMaxTries()),
|
|
'force' => $this->getParameterValue('force', in_array('force', $parameters) ? true : $workerConfig->getForce()),
|
|
'stopWhenEmpty' => $this->getParameterValue('stop-when-empty', in_array('stop-when-empty', $parameters) ? true : $workerConfig->getStopWhenEmpty()),
|
|
'maxJobs' => $this->getParameterValue('max-jobs', $workerConfig->getMaxJobs()),
|
|
'maxTime' => $this->getParameterValue('max-time', $workerConfig->getMaxTime()),
|
|
'rest' => $this->getParameterValue('rest', $workerConfig->getRest()),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Listen for the queue events in order to update the console output.
|
|
*
|
|
*/
|
|
protected function listenForEvents(): void
|
|
{
|
|
$events = app()['events'];
|
|
|
|
$events->listen(JobProcessing::class, function ($event) {
|
|
$this->writeOutput($event->job, 'starting');
|
|
});
|
|
|
|
$events->listen(JobProcessed::class, function ($event) {
|
|
$this->writeOutput($event->job, 'success');
|
|
});
|
|
|
|
$events->listen(JobFailed::class, function ($event) {
|
|
$this->writeOutput($event->job, 'failed');
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Write the status output for the queue worker.
|
|
*
|
|
* @param string $status
|
|
*
|
|
*/
|
|
protected function writeOutput(Job $job, $status): void
|
|
{
|
|
match ($status) {
|
|
'starting' => $this->writeStatus($job, 'Processing', 'comment'),
|
|
'success' => $this->writeStatus($job, 'Processed', 'info'),
|
|
'failed' => $this->writeStatus($job, 'Failed', 'error'),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Format the status output for the queue worker.
|
|
*
|
|
* @param string $status
|
|
* @param string $type
|
|
*/
|
|
protected function writeStatus(Job $job, $status, $type): void
|
|
{
|
|
$this->getCommandInterface()->getOutput()->writeln(sprintf(
|
|
"<{$type}>[%s][%s] %s</{$type}> %s",
|
|
Carbon::now()->format('Y-m-d H:i:s'),
|
|
$job->getJobId(),
|
|
str_pad("{$status}:", 11),
|
|
$job->resolveName()
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Print work command options information.
|
|
*/
|
|
protected function workerOptionsHelp(): void
|
|
{
|
|
$this->getCommandInterface()->line('<comment>' . __('admin.cli.tool.jobs.work.options.title') . '</comment>');
|
|
$this->getCommandInterface()->line(__('admin.cli.tool.jobs.work.options.usage') . PHP_EOL);
|
|
$this->getCommandInterface()->line('<comment>' . __('admin.cli.tool.jobs.work.options.description') . '</comment>');
|
|
|
|
$workerConfig = new WorkerConfiguration();
|
|
|
|
$options = [
|
|
'--connection[=CONNECTION]' => __('admin.cli.tool.jobs.work.option.connection.description', ['default' => Config::getVar('queue', 'default_connection', 'database')]),
|
|
'--queue[=QUEUE]' => __('admin.cli.tool.jobs.work.option.queue.description', ['default' => Config::getVar('queue', 'default_queue', 'queue')]),
|
|
'--name[=NAME]' => __('admin.cli.tool.jobs.work.option.name.description', ['default' => $workerConfig->getName()]),
|
|
'--backoff[=BACKOFF]' => __('admin.cli.tool.jobs.work.option.backoff.description', ['default' => $workerConfig->getBackoff()]),
|
|
'--memory[=MEMORY]' => __('admin.cli.tool.jobs.work.option.memory.description', ['default' => $workerConfig->getMemory()]),
|
|
'--timeout[=TIMEOUT]' => __('admin.cli.tool.jobs.work.option.timeout.description', ['default' => $workerConfig->getTimeout()]),
|
|
'--sleep[=SLEEP]' => __('admin.cli.tool.jobs.work.option.sleep.description', ['default' => $workerConfig->getSleep()]),
|
|
'--tries[=TRIES]' => __('admin.cli.tool.jobs.work.option.tries.description', ['default' => $workerConfig->getMaxTries()]),
|
|
'--force' => __('admin.cli.tool.jobs.work.option.force.description', ['default' => $workerConfig->getForce() ? 'true' : 'false']),
|
|
'--stop-when-empty' => __('admin.cli.tool.jobs.work.option.stopWhenEmpty.description', ['default' => $workerConfig->getStopWhenEmpty() ? 'true' : 'false']),
|
|
'--max-jobs[=MAX-JOBS]' => __('admin.cli.tool.jobs.work.option.maxJobs.description', ['default' => $workerConfig->getMaxJobs()]),
|
|
'--max-time[=MAX-TIME]' => __('admin.cli.tool.jobs.work.option.maxTime.description', ['default' => $workerConfig->getMaxTime()]),
|
|
'--rest[=REST]' => __('admin.cli.tool.jobs.work.option.rest.description', ['default' => $workerConfig->getRest()]),
|
|
'--test' => __('admin.cli.tool.jobs.work.option.test.description'),
|
|
];
|
|
|
|
$this->printUsage($options, false);
|
|
}
|
|
|
|
/**
|
|
* Print given options in a pretty way.
|
|
*/
|
|
protected function printUsage(array $options, bool $shouldTranslate = true): void
|
|
{
|
|
$width = $this->getColumnWidth(array_keys($options));
|
|
|
|
foreach ($options as $commandName => $description) {
|
|
$spacingWidth = $width - Helper::width($commandName);
|
|
$this->getCommandInterface()->line(
|
|
sprintf(
|
|
' <info>%s</info>%s%s',
|
|
$commandName,
|
|
str_repeat(' ', $spacingWidth),
|
|
$shouldTranslate ? __($description) : $description
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display the queued/failed jobs quantity
|
|
*/
|
|
protected function total(): void
|
|
{
|
|
$parameterList = $this->getParameterList();
|
|
|
|
$total = in_array('--failed', $parameterList)
|
|
? Repo::failedJob()->total()
|
|
: Repo::job()->total();
|
|
|
|
$outputInterface = $this->getCommandInterface()->getOutput();
|
|
|
|
if (in_array('--failed', $parameterList)) {
|
|
$method = $total > 0 ? 'error' : 'success';
|
|
$outputInterface->{$method}(__('admin.cli.tool.jobs.total.failed.jobs', ['total' => $total]));
|
|
return;
|
|
}
|
|
|
|
$outputInterface->warning(__('admin.cli.tool.jobs.total.jobs', ['total' => $total]));
|
|
}
|
|
|
|
/**
|
|
* Parse and execute the command
|
|
*/
|
|
public function execute()
|
|
{
|
|
if (!isset(self::AVAILABLE_OPTIONS[$this->option])) {
|
|
throw new CommandNotFoundException(
|
|
__('admin.cli.tool.jobs.option.doesnt.exists', ['option' => $this->option]),
|
|
array_keys(self::AVAILABLE_OPTIONS)
|
|
);
|
|
}
|
|
|
|
$this->{$this->option}();
|
|
}
|
|
}
|
|
|
|
try {
|
|
$tool = new commandJobs($argv ?? []);
|
|
$tool->execute();
|
|
} catch (Throwable $e) {
|
|
$output = new commandInterface();
|
|
|
|
if ($e instanceof CommandInvalidArgumentException) {
|
|
$output->errorBlock([$e->getMessage()]);
|
|
|
|
return;
|
|
}
|
|
|
|
if ($e instanceof CommandNotFoundException) {
|
|
$alternatives = $e->getAlternatives();
|
|
|
|
$message = __('admin.cli.tool.jobs.mean.those') . PHP_EOL . implode(PHP_EOL, $alternatives);
|
|
|
|
$output->errorBlock([$e->getMessage(), $message]);
|
|
|
|
return;
|
|
}
|
|
|
|
throw $e;
|
|
}
|