diff options
author | Julien Veyssier <julien-nc@posteo.net> | 2024-07-15 13:30:59 +0200 |
---|---|---|
committer | Julien Veyssier <julien-nc@posteo.net> | 2024-07-23 17:12:38 +0200 |
commit | c120a64ba2031817113a0194fd6f2337a4dc420b (patch) | |
tree | a3c9734e2dcc5a86502a2768456b9ce34c556b3c /core | |
parent | df086a8c207ec6765a94955f6638fa7aacf4c06a (diff) | |
download | nextcloud-server-c120a64ba2031817113a0194fd6f2337a4dc420b.tar.gz nextcloud-server-c120a64ba2031817113a0194fd6f2337a4dc420b.zip |
feat(taskprocessing): add occ commands to list tasks and compute stats
Signed-off-by: Julien Veyssier <julien-nc@posteo.net>
Diffstat (limited to 'core')
-rw-r--r-- | core/Command/TaskProcessing/ListCommand.php | 84 | ||||
-rw-r--r-- | core/Command/TaskProcessing/Statistics.php | 145 | ||||
-rw-r--r-- | core/Migrations/Version30000Date20240708160048.php | 6 | ||||
-rw-r--r-- | core/register_command.php | 3 |
4 files changed, 235 insertions, 3 deletions
diff --git a/core/Command/TaskProcessing/ListCommand.php b/core/Command/TaskProcessing/ListCommand.php new file mode 100644 index 00000000000..92897c8b9ea --- /dev/null +++ b/core/Command/TaskProcessing/ListCommand.php @@ -0,0 +1,84 @@ +<?php +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\Core\Command\TaskProcessing; + +use OC\Core\Command\Base; +use OCP\TaskProcessing\IManager; +use OCP\TaskProcessing\Task; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class ListCommand extends Base { + public function __construct( + protected IManager $taskProcessingManager, + ) { + parent::__construct(); + } + + protected function configure() { + $this + ->setName('taskprocessing:task:list') + ->setDescription('list tasks') + ->addOption( + 'userIdFilter', + 'u', + InputOption::VALUE_OPTIONAL, + 'only get the tasks for one user ID' + ) + ->addOption( + 'type', + 't', + InputOption::VALUE_OPTIONAL, + 'only get the tasks for one task type' + ) + ->addOption( + 'customId', + null, + InputOption::VALUE_OPTIONAL, + 'only get the tasks for one custom ID' + ) + ->addOption( + 'status', + 's', + InputOption::VALUE_OPTIONAL, + 'only get the tasks that have a specific status (STATUS_UNKNOWN=0, STATUS_SCHEDULED=1, STATUS_RUNNING=2, STATUS_SUCCESSFUL=3, STATUS_FAILED=4, STATUS_CANCELLED=5)' + ) + ->addOption( + 'scheduledAfter', + null, + InputOption::VALUE_OPTIONAL, + 'only get the tasks that were scheduled after a specific date (Unix timestamp)' + ) + ->addOption( + 'endedBefore', + null, + InputOption::VALUE_OPTIONAL, + 'only get the tasks that ended before a specific date (Unix timestamp)' + ); + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $userIdFilter = $input->getOption('userIdFilter'); + if ($userIdFilter === null) { + $userIdFilter = ''; + } elseif ($userIdFilter === '') { + $userIdFilter = null; + } + $type = $input->getOption('type'); + $customId = $input->getOption('customId'); + $status = $input->getOption('status'); + $scheduledAfter = $input->getOption('scheduledAfter'); + $endedBefore = $input->getOption('endedBefore'); + + $tasks = $this->taskProcessingManager->getTasks($userIdFilter, $type, $customId, $status, $scheduledAfter, $endedBefore); + $arrayTasks = array_map(fn (Task $task): array => $task->jsonSerialize(), $tasks); + + $this->writeArrayInOutputFormat($input, $output, $arrayTasks); + return 0; + } +} diff --git a/core/Command/TaskProcessing/Statistics.php b/core/Command/TaskProcessing/Statistics.php new file mode 100644 index 00000000000..b0e716337f0 --- /dev/null +++ b/core/Command/TaskProcessing/Statistics.php @@ -0,0 +1,145 @@ +<?php +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OC\Core\Command\TaskProcessing; + +use OC\Core\Command\Base; +use OCP\TaskProcessing\IManager; +use OCP\TaskProcessing\Task; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; + +class Statistics extends Base { + public function __construct( + protected IManager $taskProcessingManager, + ) { + parent::__construct(); + } + + protected function configure() { + $this + ->setName('taskprocessing:task:stats') + ->setDescription('get statistics for tasks') + ->addOption( + 'userIdFilter', + 'u', + InputOption::VALUE_OPTIONAL, + 'only get the tasks for one user ID' + ) + ->addOption( + 'type', + 't', + InputOption::VALUE_OPTIONAL, + 'only get the tasks for one task type' + ) + ->addOption( + 'customId', + null, + InputOption::VALUE_OPTIONAL, + 'only get the tasks for one custom ID' + ) + ->addOption( + 'status', + 's', + InputOption::VALUE_OPTIONAL, + 'only get the tasks that have a specific status (STATUS_UNKNOWN=0, STATUS_SCHEDULED=1, STATUS_RUNNING=2, STATUS_SUCCESSFUL=3, STATUS_FAILED=4, STATUS_CANCELLED=5)' + ) + ->addOption( + 'scheduledAfter', + null, + InputOption::VALUE_OPTIONAL, + 'only get the tasks that were scheduled after a specific date (Unix timestamp)' + ) + ->addOption( + 'endedBefore', + null, + InputOption::VALUE_OPTIONAL, + 'only get the tasks that ended before a specific date (Unix timestamp)' + ); + parent::configure(); + } + + protected function execute(InputInterface $input, OutputInterface $output): int { + $userIdFilter = $input->getOption('userIdFilter'); + if ($userIdFilter === null) { + $userIdFilter = ''; + } elseif ($userIdFilter === '') { + $userIdFilter = null; + } + $type = $input->getOption('type'); + $customId = $input->getOption('customId'); + $status = $input->getOption('status'); + $scheduledAfter = $input->getOption('scheduledAfter'); + $endedBefore = $input->getOption('endedBefore'); + + $tasks = $this->taskProcessingManager->getTasks($userIdFilter, $type, $customId, $status, $scheduledAfter, $endedBefore); + + $stats = ['Number of tasks' => count($tasks)]; + + $maxRunningTime = 0; + $totalRunningTime = 0; + $runningTimeCount = 0; + + $maxQueuingTime = 0; + $totalQueuingTime = 0; + $queuingTimeCount = 0; + + $maxUserWaitingTime = 0; + $totalUserWaitingTime = 0; + $userWaitingTimeCount = 0; + foreach ($tasks as $task) { + // running time + if ($task->getStartedAt() !== null && $task->getEndedAt() !== null) { + $taskRunningTime = $task->getEndedAt() - $task->getStartedAt(); + $totalRunningTime += $taskRunningTime; + $runningTimeCount++; + if ($taskRunningTime >= $maxRunningTime) { + $maxRunningTime = $taskRunningTime; + } + } + // queuing time + if ($task->getScheduledAt() !== null && $task->getStartedAt() !== null) { + $taskQueuingTime = $task->getStartedAt() - $task->getScheduledAt(); + $totalQueuingTime += $taskQueuingTime; + $queuingTimeCount++; + if ($taskQueuingTime >= $maxQueuingTime) { + $maxQueuingTime = $taskQueuingTime; + } + } + // user waiting time + if ($task->getScheduledAt() !== null && $task->getEndedAt() !== null) { + $taskUserWaitingTime = $task->getEndedAt() - $task->getScheduledAt(); + $totalUserWaitingTime += $taskUserWaitingTime; + $userWaitingTimeCount++; + if ($taskUserWaitingTime >= $maxUserWaitingTime) { + $maxUserWaitingTime = $taskUserWaitingTime; + } + } + } + + if ($runningTimeCount > 0) { + $stats['Max running time'] = $maxRunningTime; + $averageRunningTime = (int)($totalRunningTime / $runningTimeCount); + $stats['Average running time'] = $averageRunningTime; + $stats['Running time count'] = $runningTimeCount; + } + if ($queuingTimeCount > 0) { + $stats['Max queuing time'] = $maxQueuingTime; + $averageQueuingTime = (int)($totalQueuingTime / $queuingTimeCount); + $stats['Average queuing time'] = $averageQueuingTime; + $stats['Queuing time count'] = $queuingTimeCount; + } + if ($userWaitingTimeCount > 0) { + $stats['Max user waiting time'] = $maxUserWaitingTime; + $averageUserWaitingTime = (int)($totalUserWaitingTime / $userWaitingTimeCount); + $stats['Average user waiting time'] = $averageUserWaitingTime; + $stats['User waiting time count'] = $userWaitingTimeCount; + } + + $this->writeArrayInOutputFormat($input, $output, $stats); + return 0; + } +} diff --git a/core/Migrations/Version30000Date20240708160048.php b/core/Migrations/Version30000Date20240708160048.php index a85eea2c974..0b5596a05a9 100644 --- a/core/Migrations/Version30000Date20240708160048.php +++ b/core/Migrations/Version30000Date20240708160048.php @@ -34,17 +34,17 @@ class Version30000Date20240708160048 extends SimpleMigrationStep { $table->addColumn('scheduled_at', Types::INTEGER, [ 'notnull' => false, - 'default' => 0, + 'default' => null, 'unsigned' => true, ]); $table->addColumn('started_at', Types::INTEGER, [ 'notnull' => false, - 'default' => 0, + 'default' => null, 'unsigned' => true, ]); $table->addColumn('ended_at', Types::INTEGER, [ 'notnull' => false, - 'default' => 0, + 'default' => null, 'unsigned' => true, ]); diff --git a/core/register_command.php b/core/register_command.php index 6560f63d797..6e89568cf9b 100644 --- a/core/register_command.php +++ b/core/register_command.php @@ -140,6 +140,9 @@ if ($config->getSystemValueBool('installed', false)) { $application->add(Server::get(Command\Security\BruteforceResetAttempts::class)); $application->add(Server::get(Command\SetupChecks::class)); $application->add(Server::get(Command\FilesMetadata\Get::class)); + + $application->add(Server::get(Command\TaskProcessing\ListCommand::class)); + $application->add(Server::get(Command\TaskProcessing\Statistics::class)); } else { $application->add(Server::get(Command\Maintenance\Install::class)); } |