mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-29 19:13:49 +00:00
Add test for detecting stale workflows and enhance handler
Added a new test to check if workflows are stale in EntityWorkflowTest. Enhanced CancelStaleWorkflowHandler to handle stale workflows more accurately, including checking if workflows have transitioned recently. Updated EntityWorkflow entity to cascade remove workflow steps. Refactor tests for handler, to avoid using $kernel during tests
This commit is contained in:
@@ -12,6 +12,7 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Service\Workflow;
|
||||
|
||||
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
|
||||
use Chill\MainBundle\Workflow\WorkflowTransitionContextDTO;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Clock\ClockInterface;
|
||||
@@ -20,58 +21,68 @@ use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
|
||||
use Symfony\Component\Workflow\Registry;
|
||||
|
||||
#[AsMessageHandler]
|
||||
class CancelStaleWorkflowHandler
|
||||
final readonly class CancelStaleWorkflowHandler
|
||||
{
|
||||
public const string KEEP_INTERVAL = 'P90D';
|
||||
|
||||
public function __construct(private readonly EntityWorkflowRepository $workflowRepository, private readonly Registry $registry, private readonly EntityManagerInterface $em, private readonly LoggerInterface $logger, private readonly ClockInterface $clock) {}
|
||||
public function __construct(
|
||||
private EntityWorkflowRepository $workflowRepository,
|
||||
private Registry $registry,
|
||||
private EntityManagerInterface $em,
|
||||
private LoggerInterface $logger,
|
||||
private ClockInterface $clock,
|
||||
) {}
|
||||
|
||||
public function __invoke(CancelStaleWorkflowMessage $message): void
|
||||
{
|
||||
$workflowId = $message->getWorkflowId();
|
||||
$olderThanDate = $this->clock->now()->sub(new \DateInterval(CancelStaleWorkflowCronJob::KEEP_INTERVAL));
|
||||
|
||||
$olderThanDate = $this->clock->now()->sub(new \DateInterval(self::KEEP_INTERVAL));
|
||||
$staleWorkflows = $this->workflowRepository->findWorkflowsWithoutFinalStepAndOlderThan($olderThanDate);
|
||||
$workflow = $this->workflowRepository->find($message->getWorkflowId());
|
||||
if (null === $workflow) {
|
||||
$this->logger->alert('Workflow was not found!', [$workflowId]);
|
||||
|
||||
$workflow = $this->workflowRepository->find($workflowId);
|
||||
|
||||
if (!in_array($workflow, $staleWorkflows, true)) {
|
||||
$this->logger->alert('Workflow has transitioned in the meantime.', [$workflowId]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $workflow) {
|
||||
$this->logger->alert('Workflow was not found!', [$workflowId]);
|
||||
return;
|
||||
if (false === $workflow->isStaledAt($olderThanDate)) {
|
||||
$this->logger->alert('Workflow has transitioned in the meantime.', [$workflowId]);
|
||||
|
||||
throw new UnrecoverableMessageHandlingException('the workflow is not staled any more');
|
||||
}
|
||||
|
||||
$workflowComponent = $this->registry->get($workflow, $workflow->getWorkflowName());
|
||||
$metadataStore = $workflowComponent->getMetadataStore();
|
||||
$transitions = $workflowComponent->getEnabledTransitions($workflow);
|
||||
$steps = $workflow->getSteps();
|
||||
|
||||
$transitionApplied = false;
|
||||
$wasInInitialPosition = 'initial' === $workflow->getStep();
|
||||
|
||||
if (1 === count($steps)) {
|
||||
$this->em->remove($workflow->getCurrentStep());
|
||||
$this->em->remove($workflow);
|
||||
} else {
|
||||
foreach ($transitions as $transition) {
|
||||
$isFinal = $metadataStore->getMetadata('isFinal', $transition);
|
||||
$isFinalPositive = $metadataStore->getMetadata('isFinalPositive', $transition);
|
||||
foreach ($transitions as $transition) {
|
||||
$isFinal = $metadataStore->getMetadata('isFinal', $transition);
|
||||
$isFinalPositive = $metadataStore->getMetadata('isFinalPositive', $transition);
|
||||
|
||||
if ($isFinal && !$isFinalPositive) {
|
||||
$workflowComponent->apply($workflow, $transition->getName());
|
||||
$this->logger->info('EntityWorkflow has been cancelled automatically.', [$workflowId]);
|
||||
$transitionApplied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$transitionApplied) {
|
||||
$this->logger->error('No valid transition found for EntityWorkflow.', [$workflowId]);
|
||||
throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId));
|
||||
if ($isFinal && !$isFinalPositive) {
|
||||
$dto = new WorkflowTransitionContextDTO($workflow);
|
||||
$workflowComponent->apply($workflow, $transition->getName(), [
|
||||
'context' => $dto,
|
||||
'byUser' => null,
|
||||
'transitionAt' => $this->clock->now(),
|
||||
'transition' => $transition->getName(),
|
||||
]);
|
||||
$this->logger->info('EntityWorkflow has been cancelled automatically.', [$workflowId]);
|
||||
$transitionApplied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$transitionApplied) {
|
||||
$this->logger->error('No valid transition found for EntityWorkflow.', [$workflowId]);
|
||||
throw new UnrecoverableMessageHandlingException(sprintf('No valid transition found for EntityWorkflow %d.', $workflowId));
|
||||
}
|
||||
|
||||
if ($wasInInitialPosition) {
|
||||
$this->em->remove($workflow);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user