Submit
Path:
~
/
/
proc
/
self
/
root
/
opt
/
psa
/
admin
/
plib
/
modules
/
wp-toolkit
/
vendor
/
plesk
/
background-tasks
/
src
/
Executor
/
File Content:
SaasExecutor.php
<?php // Copyright 1999-2024. WebPros International GmbH. All rights reserved. namespace BackgroundTasks\Executor; use BackgroundTasks\Adapter\SaasStepProgressAdapter; use BackgroundTasks\Adapter\SaasTaskProgressAdapter; use BackgroundTasks\BaseComplexTask; use BackgroundTasks\BaseTaskInterface; use BackgroundTasks\ComplexTaskInterface; use BackgroundTasks\DatabaseStorage\BackgroundTaskBrokerInterface; use BackgroundTasks\DatabaseStorage\BackgroundTaskParamsBrokerInterface; use BackgroundTasks\DatabaseStorage\BackgroundTaskRowInterface; use BackgroundTasks\DataStorage\SaasTaskDataStorage; use BackgroundTasks\DataStorage\TaskDataStorageInterface; use BackgroundTasks\Exception\NotRollbackableStepException; use BackgroundTasks\Exception\NotRollbackableTaskException; use BackgroundTasks\Exception\TaskHasWrongStatusException; use BackgroundTasks\Exception\TaskNotFoundException; use BackgroundTasks\Exception\UnknownTaskType; use BackgroundTasks\Helper\StepHelper; use BackgroundTasks\Model\BackgroundTasksCollectionInterface; use BackgroundTasks\Progress\StepProgressInterface; use BackgroundTasks\Progress\TaskProgressInterface; use BackgroundTasks\RollbackableTaskInterface; use BackgroundTasks\SimpleTaskInterface; use BackgroundTasks\Step\RollbackableStepInterface; use BackgroundTasks\Step\StepInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; class SaasExecutor { /** * @var BackgroundTasksCollectionInterface */ private $backgroundTasksCollection; /** * @var BackgroundTaskBrokerInterface */ private $backgroundTaskBroker; /** * @var LoggerInterface */ private $logger; /** * @var BackgroundTaskParamsBrokerInterface */ private $backgroundTaskParamsBroker; public function __construct(BackgroundTasksCollectionInterface $backgroundTasksCollection, BackgroundTaskBrokerInterface $backgroundTaskBroker, BackgroundTaskParamsBrokerInterface $backgroundTaskParamsBroker, ?LoggerInterface $logger = null) { $this->backgroundTasksCollection = $backgroundTasksCollection; $this->backgroundTaskBroker = $backgroundTaskBroker; $this->backgroundTaskParamsBroker = $backgroundTaskParamsBroker; $this->logger = $logger ?: new NullLogger(); } /** * @param int $id * @throws TaskNotFoundException * @throws TaskHasWrongStatusException * @throws UnknownTaskType * @throws \Exception */ public function execute(int $id) : void { $longTask = $this->backgroundTaskBroker->getById($id); if (\is_null($longTask)) { throw new TaskNotFoundException("Task with id {$id} not found in database"); } if ($longTask->getStatus() === BaseTaskInterface::STATUS_CANCELED) { $this->logger->debug("Task {$longTask->getCode()} has been cancelled"); return; } if ($longTask->getStatus() !== BaseTaskInterface::STATUS_STARTED) { $expectedStatus = BaseTaskInterface::STATUS_STARTED; throw new TaskHasWrongStatusException("Task with id {$id} must be in status {$expectedStatus}, but now it has status {$longTask->getStatus()}"); } $executableTask = $this->backgroundTasksCollection->getByCode($longTask->getCode()); $taskData = new SaasTaskDataStorage($longTask, $this->backgroundTaskParamsBroker); if ($executableTask instanceof ComplexTaskInterface) { $taskProgress = new SaasTaskProgressAdapter($longTask, $executableTask->getExecutionOptions()->isTaskProgressControlledManually()); $stepProgress = new SaasStepProgressAdapter($taskData); $this->executeComplexTask($executableTask, $longTask, $taskData, $taskProgress, $stepProgress); } elseif ($executableTask instanceof SimpleTaskInterface) { $taskProgress = new SaasTaskProgressAdapter($longTask, \true); $this->executeSimpleTask($executableTask, $longTask, $taskData, $taskProgress); } else { // should never reach that code throw new UnknownTaskType('Unknown task type'); } } /** * @param SimpleTaskInterface $executableTask * @param BackgroundTaskRowInterface $task * @param TaskDataStorageInterface $taskData * @param TaskProgressInterface $taskProgress */ public function executeSimpleTask(SimpleTaskInterface $executableTask, BackgroundTaskRowInterface $task, TaskDataStorageInterface $taskData, TaskProgressInterface $taskProgress) { if ($task->getStatus() === BaseTaskInterface::STATUS_CANCELED) { $this->logger->debug("Task {$executableTask->getCode()} has been cancelled"); return; } try { $parametersString = \var_export($taskData->getInitialTaskParams(), \true); $this->logger->debug("Starting execution '{$executableTask->getCode()}' task with parameters: {$parametersString}"); $task->setStatus(BaseComplexTask::STATUS_STARTED); $executableTask->onStart($taskData); $task->setStatus(BaseComplexTask::STATUS_RUNNING); $executableTask->run($taskProgress, $taskData); $task->setProgress(100); $executableTask->onDone($taskData); $task->setStatus(BaseComplexTask::STATUS_DONE); } catch (\Exception $exception) { $executableTask->onError($taskData, $exception); $this->addUniqueLastError($exception, $taskData); $task->setStatus(BaseComplexTask::STATUS_ERROR); } finally { $this->logger->debug("Stopping execution '{$executableTask->getCode()}' task"); } } /** * @param ComplexTaskInterface $executableTask * @param BackgroundTaskRowInterface $task * @param TaskDataStorageInterface $taskData * @param TaskProgressInterface $taskProgress * @param StepProgressInterface $stepProgress */ public function executeComplexTask(ComplexTaskInterface $executableTask, BackgroundTaskRowInterface $task, TaskDataStorageInterface $taskData, TaskProgressInterface $taskProgress, StepProgressInterface $stepProgress) { if ($task->getStatus() === BaseTaskInterface::STATUS_CANCELED) { $this->logger->debug("Task {$executableTask->getCode()} has been cancelled"); return; } try { $parametersString = \var_export($taskData->getInitialTaskParams(), \true); $this->logger->debug("Starting execution '{$executableTask->getCode()}' task with parameters: {$parametersString}"); $task->setStatus(BaseComplexTask::STATUS_STARTED); $steps = $executableTask->getSteps($taskData); $stepsCount = \count(StepHelper::getVisibleSteps($steps)); $progressPerStep = 100 / ($stepsCount > 0 ? $stepsCount : 1); $executableTask->onStart($taskData); $task->setStatus(BaseComplexTask::STATUS_RUNNING); $shouldRollback = \false; $runStepsIterator = 0; foreach ($steps as $step) { $this->logger->debug("Executing '{$step->getCode()}' step"); // Set initial values, so data from previous step doesn't affect current one $taskData->setPrivateParam(StepProgressInterface::CURRENT_STEP_PROGRESS, -1); $taskData->setPrivateParam(StepProgressInterface::CURRENT_STEP_HINT, ''); $step->run($stepProgress, $taskProgress, $taskData); $runStepsIterator++; $currentStepProgress = $taskData->getPrivateParam(StepProgressInterface::CURRENT_STEP_PROGRESS, -1); if ($currentStepProgress >= 0) { $taskData->setPrivateParam(StepProgressInterface::CURRENT_STEP_PROGRESS, 100); } if (!$step->isHidden() && !$executableTask->getExecutionOptions()->isTaskProgressControlledManually()) { $task->setProgress($task->getProgress() + $progressPerStep); } $reloadTask = $this->backgroundTaskBroker->getById($task->getId()); if ($reloadTask === null) { throw new TaskNotFoundException("Task with id {$task->getId()} not found in database"); } if ($reloadTask->getStatus() === BaseTaskInterface::STATUS_CANCELED) { $this->logger->debug("Task {$executableTask->getCode()} has been cancelled, rolling back"); $shouldRollback = \true; break; } } if ($shouldRollback) { $this->logger->debug("Starting rollback for '{$executableTask->getCode()}' task"); if (!$executableTask instanceof RollbackableTaskInterface) { throw new NotRollbackableTaskException("Task {$executableTask->getCode()} is not rollbackable but is trying to be rolled back"); } $this->rollback($steps, $executableTask, $task, $taskData, $runStepsIterator); } else { $task->setProgress(100); $executableTask->onDone($taskData); $task->setStatus(BaseComplexTask::STATUS_DONE); } } catch (\Exception $exception) { $executableTask->onError($taskData, $exception); $this->addUniqueLastError($exception, $taskData); $task->setStatus(BaseComplexTask::STATUS_ERROR); } finally { $this->logger->debug("Stopping execution '{$executableTask->getCode()}' task"); } } /** * @param StepInterface[] $steps * @throws NotRollbackableStepException */ private function rollback(array $steps, RollbackableTaskInterface $executableTask, BackgroundTaskRowInterface $task, TaskDataStorageInterface $taskData, int $lastStepIndex) { $steps = \array_reverse($steps); $stepsCount = \count($steps); $visibleStepsCount = \count(StepHelper::getVisibleSteps($steps)); $progressPerStep = 100 / ($visibleStepsCount > 0 ? $visibleStepsCount : 1); $reversedLastStepIndex = $stepsCount - $lastStepIndex; foreach ($steps as $step) { if (!$step instanceof RollbackableStepInterface) { throw new NotRollbackableStepException("Step {$step->getCode()} is not rollbackable but is trying to be rolled back"); } } foreach ($steps as $reversedStepIndex => $step) { if ($reversedLastStepIndex > $reversedStepIndex) { continue; // Skip steps that were not executed } $this->logger->debug("Rolling back '{$step->getCode()}' step"); $step->rollback($taskData); $currentStepProgress = $taskData->getPrivateParam(StepProgressInterface::CURRENT_STEP_PROGRESS, -1); if ($currentStepProgress >= 0) { $taskData->setPrivateParam(StepProgressInterface::CURRENT_STEP_PROGRESS, 0); } if (!$step->isHidden() && !$executableTask->getExecutionOptions()->isTaskProgressControlledManually()) { $task->setProgress($task->getProgress() - $progressPerStep); } } $task->setProgress(0); $executableTask->onRollback($taskData); } /** * @param \Exception $exception * @param TaskDataStorageInterface $memoryTaskData */ private function addUniqueLastError(\Exception $exception, TaskDataStorageInterface $memoryTaskData) { // Developer can catch all exceptions himself, store error in task data and throw it upper, // so need to check that last stored error isn't equal to current $errorMessage = $exception->getMessage(); $errors = $memoryTaskData->getErrors(); $lastError = \end($errors); if ($lastError !== $errorMessage) { $memoryTaskData->addError($errorMessage); $this->logger->error($errorMessage); $this->logger->debug($exception); } } }
Edit
Rename
Chmod
Delete
FILE
FOLDER
INFO
Name
Size
Permission
Action
ConsoleTasks
---
0755
SaasExecutor.php
12110 bytes
0644
SynchronousExecutor.php
3857 bytes
0644
N4ST4R_ID | Naxtarrr