-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from Setono/handle-stuck-orders
Handle upload order requests that are stuck in 'processing' state
- Loading branch information
Showing
18 changed files
with
319 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
src/Event/FailedUploadOrderRequestsQueryBuilderCreatedEvent.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\Event; | ||
|
||
use Doctrine\ORM\QueryBuilder; | ||
|
||
/** | ||
* This event is fired when the query builder for failed upload order requests has been created. | ||
* Listen to this event if you want to filter on associated orders of the upload order requests. | ||
*/ | ||
final class FailedUploadOrderRequestsQueryBuilderCreatedEvent | ||
{ | ||
public function __construct(public readonly QueryBuilder $queryBuilder) | ||
{ | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/EventSubscriber/Workflow/UploadOrderRequest/IncrementTriesSubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\EventSubscriber\Workflow\UploadOrderRequest; | ||
|
||
use Setono\SyliusPeakPlugin\Model\UploadOrderRequestInterface; | ||
use Setono\SyliusPeakPlugin\Workflow\UploadOrderRequestWorkflow; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\Workflow\Event\CompletedEvent; | ||
use Webmozart\Assert\Assert; | ||
|
||
final class IncrementTriesSubscriber implements EventSubscriberInterface | ||
{ | ||
public static function getSubscribedEvents(): array | ||
{ | ||
return [sprintf('workflow.%s.completed.%s', UploadOrderRequestWorkflow::NAME, UploadOrderRequestWorkflow::TRANSITION_PROCESS) => 'incrementTries']; | ||
} | ||
|
||
public function incrementTries(CompletedEvent $event): void | ||
{ | ||
/** @var UploadOrderRequestInterface|object $uploadOrderRequest */ | ||
$uploadOrderRequest = $event->getSubject(); | ||
Assert::isInstanceOf($uploadOrderRequest, UploadOrderRequestInterface::class); | ||
|
||
$uploadOrderRequest->incrementTries(); | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
src/EventSubscriber/Workflow/UploadOrderRequest/RetrySubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\EventSubscriber\Workflow\UploadOrderRequest; | ||
|
||
use Setono\SyliusPeakPlugin\Model\UploadOrderRequestInterface; | ||
use Setono\SyliusPeakPlugin\Workflow\UploadOrderRequestWorkflow; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\Workflow\Event\CompletedEvent; | ||
use Webmozart\Assert\Assert; | ||
|
||
final class RetrySubscriber implements EventSubscriberInterface | ||
{ | ||
public function __construct(private readonly int $maxTries = 5) | ||
{ | ||
} | ||
|
||
public static function getSubscribedEvents(): array | ||
{ | ||
return [sprintf('workflow.%s.completed.%s', UploadOrderRequestWorkflow::NAME, UploadOrderRequestWorkflow::TRANSITION_FAIL) => 'retry']; | ||
} | ||
|
||
public function retry(CompletedEvent $event): void | ||
{ | ||
/** @var UploadOrderRequestInterface|object $uploadOrderRequest */ | ||
$uploadOrderRequest = $event->getSubject(); | ||
Assert::isInstanceOf($uploadOrderRequest, UploadOrderRequestInterface::class); | ||
|
||
if ($uploadOrderRequest->getTries() >= $this->maxTries) { | ||
return; | ||
} | ||
|
||
$event->getWorkflow()->apply($uploadOrderRequest, UploadOrderRequestWorkflow::TRANSITION_RESET); | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/EventSubscriber/Workflow/UploadOrderRequest/StateUpdatedSubscriber.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\EventSubscriber\Workflow\UploadOrderRequest; | ||
|
||
use Setono\SyliusPeakPlugin\Model\UploadOrderRequestInterface; | ||
use Setono\SyliusPeakPlugin\Workflow\UploadOrderRequestWorkflow; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
use Symfony\Component\Workflow\Event\CompletedEvent; | ||
use Webmozart\Assert\Assert; | ||
|
||
final class StateUpdatedSubscriber implements EventSubscriberInterface | ||
{ | ||
public static function getSubscribedEvents(): array | ||
{ | ||
return [sprintf('workflow.%s.completed', UploadOrderRequestWorkflow::NAME) => 'updateTimestamp']; | ||
} | ||
|
||
public function updateTimestamp(CompletedEvent $event): void | ||
{ | ||
/** @var UploadOrderRequestInterface|object $uploadOrderRequest */ | ||
$uploadOrderRequest = $event->getSubject(); | ||
Assert::isInstanceOf($uploadOrderRequest, UploadOrderRequestInterface::class); | ||
|
||
$uploadOrderRequest->setStateUpdatedAt(new \DateTimeImmutable()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\Processor; | ||
|
||
use Doctrine\ORM\OptimisticLockException; | ||
use Doctrine\Persistence\ManagerRegistry; | ||
use Setono\Doctrine\ORMTrait; | ||
use Setono\SyliusPeakPlugin\Provider\FailedUploadOrderRequestsProviderInterface; | ||
use Setono\SyliusPeakPlugin\Workflow\UploadOrderRequestWorkflow; | ||
use Symfony\Component\Workflow\Exception\LogicException; | ||
use Symfony\Component\Workflow\WorkflowInterface; | ||
|
||
final class FailedUploadOrderRequestProcessor implements FailedUploadOrderRequestProcessorInterface | ||
{ | ||
use ORMTrait; | ||
|
||
public function __construct( | ||
private readonly FailedUploadOrderRequestsProviderInterface $failedUploadOrderRequestsProvider, | ||
private readonly WorkflowInterface $uploadOrderRequestWorkflow, | ||
ManagerRegistry $managerRegistry, | ||
) { | ||
$this->managerRegistry = $managerRegistry; | ||
} | ||
|
||
public function process(): void | ||
{ | ||
foreach ($this->failedUploadOrderRequestsProvider->getUploadOrderRequests() as $uploadOrderRequest) { | ||
try { | ||
$this->uploadOrderRequestWorkflow->apply($uploadOrderRequest, UploadOrderRequestWorkflow::TRANSITION_FAIL); | ||
} catch (LogicException) { | ||
continue; | ||
} | ||
|
||
try { | ||
$this->getManager($uploadOrderRequest)->flush(); | ||
} catch (OptimisticLockException) { | ||
continue; | ||
} | ||
} | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/Processor/FailedUploadOrderRequestProcessorInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\Processor; | ||
|
||
interface FailedUploadOrderRequestProcessorInterface | ||
{ | ||
public function process(): void; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\Provider; | ||
|
||
use Doctrine\Persistence\ManagerRegistry; | ||
use DoctrineBatchUtils\BatchProcessing\SelectBatchIteratorAggregate; | ||
use Psr\EventDispatcher\EventDispatcherInterface; | ||
use Setono\Doctrine\ORMTrait; | ||
use Setono\SyliusPeakPlugin\Event\FailedUploadOrderRequestsQueryBuilderCreatedEvent; | ||
use Setono\SyliusPeakPlugin\Model\UploadOrderRequestInterface; | ||
|
||
final class FailedUploadOrderRequestsProvider implements FailedUploadOrderRequestsProviderInterface | ||
{ | ||
use ORMTrait; | ||
|
||
/** | ||
* @param class-string<UploadOrderRequestInterface> $uploadOrderRequestClass | ||
*/ | ||
public function __construct( | ||
ManagerRegistry $managerRegistry, | ||
private readonly EventDispatcherInterface $eventDispatcher, | ||
private readonly string $uploadOrderRequestClass, | ||
private readonly string $processingTimeout = '1 hour', | ||
) { | ||
$this->managerRegistry = $managerRegistry; | ||
} | ||
|
||
/** | ||
* @return \Generator<array-key, UploadOrderRequestInterface> | ||
*/ | ||
public function getUploadOrderRequests(): \Generator | ||
{ | ||
$qb = $this->getRepository($this->uploadOrderRequestClass)->createQueryBuilder('o') | ||
->andWhere('o.state = :orderState') | ||
->andWhere('o.stateUpdatedAt < :stateUpdatedAt') | ||
->setParameter('state', UploadOrderRequestInterface::STATE_PROCESSING) | ||
->setParameter('stateUpdatedAt', new \DateTimeImmutable('-' . $this->processingTimeout)) | ||
; | ||
|
||
$this->eventDispatcher->dispatch(new FailedUploadOrderRequestsQueryBuilderCreatedEvent($qb)); | ||
|
||
/** @var SelectBatchIteratorAggregate<array-key, UploadOrderRequestInterface> $iterator */ | ||
$iterator = SelectBatchIteratorAggregate::fromQuery($qb->getQuery(), 50); | ||
|
||
yield from $iterator; | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/Provider/FailedUploadOrderRequestsProviderInterface.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Setono\SyliusPeakPlugin\Provider; | ||
|
||
use Setono\SyliusPeakPlugin\Model\UploadOrderRequestInterface; | ||
|
||
interface FailedUploadOrderRequestsProviderInterface | ||
{ | ||
/** | ||
* @return iterable<array-key, UploadOrderRequestInterface> | ||
*/ | ||
public function getUploadOrderRequests(): iterable; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.