Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions Classes/Command/TaskCommandController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use Flowpack\Task\Domain\Repository\TaskExecutionRepository;
use Flowpack\Task\Domain\Runner\TaskRunner;
use Flowpack\Task\Domain\Scheduler\Scheduler;
use Flowpack\Task\Domain\Task\Task;
use Flowpack\Task\Domain\Task\TaskCollectionFactory;
use Flowpack\Task\Domain\Task\TaskExecutionHistory;
use Flowpack\Task\Domain\Task\TaskInterface;
Expand Down Expand Up @@ -154,6 +153,60 @@ public function showCommand(string $taskIdentifier): void
);
}

/**
* Clean task execution history database.
*
* Removes specified entries from the task execution history database.
*
* Can filter by task, task status or date.
*
* @param string|null $task Task Identifier
* @param string|null $before Datetime
* @param string|null $status Status, use ',' to separate multiple
* @param bool $dry Enable dryrun, does not delete entries
* @param bool $verbose Enable Verbose output
*/
public function cleanCommand(?string $task = null, ?string $before = null, ?string $status = null, bool $verbose = false, bool $dry=false): void
{
$statusArray = [];
if ($status !== null) {
foreach (explode(',', $status) as $s) {
$statusArray[] = trim($s);
}
}

$targets = $this->taskExecutionRepository->findByOptions($task, $before, $statusArray);

$confirm = true;
if (!$dry) $confirm = $this->output->askConfirmation("Do you want to delete " . (count($targets)) . " entries? [Y/n]");

if ($confirm) {
if (!$dry) $this->taskExecutionRepository->removeEntries($targets);

if ($verbose) {
$this->output->outputTable(array_map(function (TaskExecution $task) {
$label = '';
try {
$label = $this->getTaskByIdentifier($task->getTaskIdentifier())->getLabel();
} catch (StopCommandException $exception) {}
return [
$task->getTaskIdentifier(),
$label,
$task->getHandlerClass(),
$task->getStatus(),
$task->getScheduleTime()->format('Y-m-d H:i:s'),
$task->getStatus()!==TaskStatus::PLANNED ? $task->getStartTime()->format('Y-m-d H:i:s') : 'null',
$task->getStatus()!==TaskStatus::PLANNED ? $task->getEndTime()->format('Y-m-d H:i:s') : 'null',
];
}, $targets),
['Identifier', 'Label', 'Handler Class', 'Status', 'Scheduled Time', 'Start Time', 'End Time']
);

}
$this->outputLine(($dry ? "Targets " : "Removed ") . count($targets) . " entries");
}
}

/**
* @param TaskInterface $task
* @return string
Expand Down Expand Up @@ -183,4 +236,4 @@ private function getTaskByIdentifier(string $taskIdentifier): TaskInterface
$this->quit(1);
}
}
}
}
61 changes: 61 additions & 0 deletions Classes/Domain/Repository/TaskExecutionRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,67 @@ public function removePlannedTask(Task $task): void
}
}

/**
* Queries task executions by parameters.
*
* @param string|null $taskIdentifier
* @param string|null $before
* @param array $statusArray
* @return array
*/
public function findByOptions(?string $taskIdentifier, ?string $before, array $statusArray): array
{
$query = $this->createQuery();

$constraints = [];
if ($taskIdentifier !== null) {
$constraints[] = $query->equals('taskIdentifier', $taskIdentifier);
}
if ($before !== null) $constraints[] = $query->logicalOr(
$query->lessThan('endTime', $before),
$query->lessThan('scheduleTime', $before),
);
if ($statusArray) {
$statusConstraints = [];

foreach ($statusArray as $status) {
$statusConstraints[] = $query->equals('status', $status);
}

if (count($statusConstraints) === 1) {
$constraints[] = $statusConstraints[0];
} elseif (count($statusConstraints) > 1) {
$constraints[] = $query->logicalOr($statusConstraints);
}
}

if ($constraints) {
$query->matching(
$query->logicalAnd(
$constraints
)
);
}

return $query->execute()->toArray();
}

/**
* @param array $entries
* @return void
* @throws \RuntimeException
*/
public function removeEntries(array $entries): void
{
foreach ($entries as $entry) {
try {
$this->remove($entry);
} catch (ORMException|IllegalObjectTypeException $e) {
throw new \RuntimeException('Failed to remove task from execution repository', 1645610863, $e);
}
}
}

public function findLatestExecution(Task $task, int $limit = 5, int $offset = 0): QueryResultInterface
{
$query = $this->createQuery();
Expand Down
8 changes: 7 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

This package provides a simple to use task scheduler for Neos Flow. Tasks are configured via settings, recurring tasks can be configured using cron syntax. Detailed options configure the first and last executions as well as options for the class handling the task.

Scheduling and running tasks are decoupled: The `Scheduler` schedules tasks whcih the are executed by the `TaskRunner`. This architecture allows receiving and displaying metrics of already executed tasks.
Scheduling and running tasks are decoupled: The `Scheduler` schedules tasks which then are executed by the `TaskRunner`. This architecture allows receiving and displaying metrics of already executed tasks.

Most of the architectural ideas behind the package are taken from [php-task](https://github.com/php-task/php-task), and reimplemented for Neos Flow.

Expand Down Expand Up @@ -81,3 +81,9 @@ Show details about a specific task:
```bash
./flow task:show <taskIdentifier>
```

Truncate task history database:

```bash
./flow task:clean [--task=<taskIdentifier>] [--status=<status>] [--before=<date>] [--dry] [--verbose]
```
Loading