Skip to content

Commit

Permalink
TE-10112 Optimized checkout performance. (#8851)
Browse files Browse the repository at this point in the history
TE-10112 Checkout Performance issues
  • Loading branch information
Dmytro Dymarchuk authored Feb 22, 2022
1 parent a620683 commit d6cc889
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/Spryker/Zed/Oms/Business/Lock/TriggerLocker.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ protected function acquireBatch(array $identifiers, ?string $details = null): bo
}

try {
$isCommitSuccess = $this->commit();
$isCommitSuccess = $this->commitIdentical();
} catch (Exception $exception) {
throw new LockException(
sprintf(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1119,17 +1119,8 @@ protected function getStateByEvent(array $orderItems)
protected function saveOrderItemsTimeout(array $orderItems, array $processes, array $sourceStateBuffer)
{
$currentTime = new DateTime('now');
foreach ($orderItems as $orderItem) {
$process = $processes[$orderItem->getProcess()->getName()];

$sourceStateId = $sourceStateBuffer[$orderItem->getIdSalesOrderItem()];
$targetStateId = $orderItem->getState()->getName();
$targetState = $process->getStateFromAllProcesses($targetStateId);

if ($targetState->hasTimeoutEvent()) {
$this->timeout->dropOldTimeout($process, $sourceStateId, $orderItem);
$this->timeout->setNewTimeout($process, $orderItem, $currentTime);
}
}
$this->timeout->dropOldTimeouts($orderItems, $processes, $sourceStateBuffer);
$this->timeout->setNewTimeouts($orderItems, $currentTime, $processes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ class PersistenceManager implements PersistenceManagerInterface
*/
protected $omsConfig;

/**
* @var array<string, \Orm\Zed\Oms\Persistence\SpyOmsOrderItemState>
*/
protected static $stateCache = [];

/**
* @var array<string, \Orm\Zed\Oms\Persistence\SpyOmsOrderProcess>
*/
protected static $processCache = [];

/**
* @param \Spryker\Zed\Oms\OmsConfig $omsConfig
*/
Expand All @@ -39,7 +49,11 @@ public function __construct(OmsConfig $omsConfig)
*/
protected function getStateEntity($stateName)
{
return $this->getTransactionHandler()->handleTransaction(function () use ($stateName): SpyOmsOrderItemState {
if (isset(static::$stateCache[$stateName])) {
return static::$stateCache[$stateName];
}

$stateEntity = $this->getTransactionHandler()->handleTransaction(function () use ($stateName): SpyOmsOrderItemState {
$stateEntity = SpyOmsOrderItemStateQuery::create()
->filterByName($stateName)
->findOneOrCreate();
Expand All @@ -50,6 +64,10 @@ protected function getStateEntity($stateName)

return $stateEntity;
});

static::$stateCache[$stateName] = $stateEntity;

return $stateEntity;
}

/**
Expand All @@ -68,7 +86,11 @@ public function getProcessEntity($processName)
));
}

return $this->getTransactionHandler()->handleTransaction(function () use ($processName): SpyOmsOrderProcess {
if (isset(static::$processCache[$processName])) {
return static::$processCache[$processName];
}

$processEntity = $this->getTransactionHandler()->handleTransaction(function () use ($processName): SpyOmsOrderProcess {
$processEntity = SpyOmsOrderProcessQuery::create()
->filterByName($processName)
->findOneOrCreate();
Expand All @@ -79,6 +101,10 @@ public function getProcessEntity($processName)

return $processEntity;
});

static::$processCache[$processName] = $processEntity;

return $processEntity;
}

/**
Expand Down
127 changes: 105 additions & 22 deletions src/Spryker/Zed/Oms/Business/OrderStateMachine/Timeout.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@
use Spryker\Zed\Oms\Business\Util\TimeoutProcessorCollectionInterface;
use Spryker\Zed\Oms\OmsConfig;
use Spryker\Zed\Oms\Persistence\OmsQueryContainerInterface;
use Spryker\Zed\Propel\Persistence\BatchProcessor\ActiveRecordBatchProcessorTrait;

class Timeout implements TimeoutInterface
{
use ActiveRecordBatchProcessorTrait;

/**
* @var \Spryker\Zed\Oms\Persistence\OmsQueryContainerInterface
*/
Expand Down Expand Up @@ -100,29 +103,10 @@ public function checkTimeouts(
*/
public function setNewTimeout(ProcessInterface $process, SpySalesOrderItem $orderItem, DateTime $currentTime)
{
$targetStateEntity = $orderItem->getState();

$targetState = $this->getStateFromProcess($targetStateEntity->getName(), $process);
$newOmsEventTimeoutEntities = $this->getNewOmsEventTimeoutEntities($orderItem, $process, $currentTime);

if ($targetState->hasTimeoutEvent()) {
$events = $targetState->getTimeoutEvents();

$handledEvents = [];
foreach ($events as $event) {
if (in_array($event->getName(), $handledEvents)) {
continue;
}

$handledEvents[] = $event->getName();
$timeoutDate = $this->calculateTimeoutDateFromEvent($currentTime, $event, $orderItem);

(new SpyOmsEventTimeout())
->setTimeout($timeoutDate)
->setOrderItem($orderItem)
->setState($targetStateEntity)
->setEvent($event->getName())
->save();
}
foreach ($newOmsEventTimeoutEntities as $newOmsEventTimeoutEntity) {
$newOmsEventTimeoutEntity->save();
}
}

Expand All @@ -144,6 +128,64 @@ public function dropOldTimeout(ProcessInterface $process, $stateId, SpySalesOrde
}
}

/**
* @param array<\Orm\Zed\Sales\Persistence\SpySalesOrderItem> $orderItems
* @param \DateTime $currentTime
* @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processes
*
* @return void
*/
public function setNewTimeouts(array $orderItems, DateTime $currentTime, array $processes): void
{
$newOmsEventTimeoutEntities = [];

foreach ($orderItems as $orderItem) {
$process = $processes[$orderItem->getProcess()->getName()];

$newOmsEventTimeoutEntities = array_merge(
$newOmsEventTimeoutEntities,
$this->getNewOmsEventTimeoutEntities($orderItem, $process, $currentTime),
);
}

if ($newOmsEventTimeoutEntities !== []) {
foreach ($newOmsEventTimeoutEntities as $newOmsEventTimeoutEntity) {
$this->persist($newOmsEventTimeoutEntity);
}

$this->commitIdentical();
}
}

/**
* @param array<\Orm\Zed\Sales\Persistence\SpySalesOrderItem> $orderItems
* @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processes
* @param array $sourceStateBuffer
*
* @return void
*/
public function dropOldTimeouts(array $orderItems, array $processes, array $sourceStateBuffer): void
{
$orderItemIdsForRemoving = [];

foreach ($orderItems as $orderItem) {
$process = $processes[$orderItem->getProcess()->getName()];

$sourceStateId = $sourceStateBuffer[$orderItem->getIdSalesOrderItem()];
$targetStateId = $orderItem->getState()->getName();
$targetState = $this->getStateFromProcess($targetStateId, $process);
$sourceState = $this->getStateFromProcess($sourceStateId, $process);

if ($targetState->hasTimeoutEvent() && $sourceState->hasTimeoutEvent()) {
$orderItemIdsForRemoving[] = $orderItem->getIdSalesOrderItem();
}
}

SpyOmsEventTimeoutQuery::create()
->filterByFkSalesOrderItem_In($orderItemIdsForRemoving)
->delete();
}

/**
* @param \DateTime $currentTime
* @param \Spryker\Zed\Oms\Business\Process\EventInterface $event
Expand Down Expand Up @@ -294,4 +336,45 @@ protected function calculateTimeoutFromTimeoutProcessor(

return (new DateTime())->setTimestamp($timeoutProcessorTimeoutResponseTransfer->getTimeoutTimestamp());
}

/**
* @param \Orm\Zed\Sales\Persistence\SpySalesOrderItem $orderItem
* @param \Spryker\Zed\Oms\Business\Process\ProcessInterface $process
* @param \DateTime $currentTime
*
* @return array<\Orm\Zed\Oms\Persistence\SpyOmsEventTimeout>
*/
protected function getNewOmsEventTimeoutEntities(
SpySalesOrderItem $orderItem,
ProcessInterface $process,
DateTime $currentTime
): array {
$targetStateEntity = $orderItem->getState();

$targetState = $this->getStateFromProcess($targetStateEntity->getName(), $process);

$omsEventTimeoutEntities = [];

if ($targetState->hasTimeoutEvent()) {
$events = $targetState->getTimeoutEvents();

$handledEvents = [];
foreach ($events as $event) {
if (in_array($event->getName(), $handledEvents)) {
continue;
}

$handledEvents[] = $event->getName();
$timeoutDate = $this->calculateTimeoutDateFromEvent($currentTime, $event, $orderItem);

$omsEventTimeoutEntities[] = (new SpyOmsEventTimeout())
->setTimeout($timeoutDate)
->setOrderItem($orderItem)
->setState($targetStateEntity)
->setEvent($event->getName());
}
}

return $omsEventTimeoutEntities;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,28 @@ public function setNewTimeout(ProcessInterface $process, SpySalesOrderItem $orde
* @return void
*/
public function dropOldTimeout(ProcessInterface $process, $stateId, SpySalesOrderItem $orderItem);

/**
* @param array<\Orm\Zed\Sales\Persistence\SpySalesOrderItem> $orderItems
* @param \DateTime $currentTime
* @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processes
*
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*
* @return void
*/
public function setNewTimeouts(array $orderItems, DateTime $currentTime, array $processes);

/**
* @param array<\Orm\Zed\Sales\Persistence\SpySalesOrderItem> $orderItems
* @param array<\Spryker\Zed\Oms\Business\Process\ProcessInterface> $processes
* @param array $sourceStateBuffer
*
* @throws \Exception
* @throws \Propel\Runtime\Exception\PropelException
*
* @return void
*/
public function dropOldTimeouts(array $orderItems, array $processes, array $sourceStateBuffer);
}
17 changes: 17 additions & 0 deletions tests/SprykerTest/Zed/Oms/_support/Helper/OmsHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
use Orm\Zed\Oms\Persistence\SpyOmsOrderItemStateQuery;
use Orm\Zed\Oms\Persistence\SpyOmsProductReservation;
use Orm\Zed\Sales\Persistence\SpySalesOrderItemQuery;
use ReflectionProperty;
use Spryker\Shared\Oms\OmsConstants;
use Spryker\Zed\Oms\Business\OmsFacade;
use Spryker\Zed\Oms\Business\OrderStateMachine\PersistenceManager;
use SprykerTest\Shared\Testify\Helper\ConfigHelperTrait;
use SprykerTest\Shared\Testify\Helper\DataCleanupHelperTrait;
use Symfony\Component\Process\Process;
Expand Down Expand Up @@ -119,6 +121,8 @@ protected function runCommand(string $command): void
*/
public function configureTestStateMachine(array $activeProcesses, ?string $xmlFolder = null): void
{
$this->clearPersistenceManagerCache();

if (!$xmlFolder) {
$xmlFolder = realpath(__DIR__ . '/../../../../../_data/state-machine/');
}
Expand Down Expand Up @@ -199,4 +203,17 @@ public function haveOmsEventTimeoutEntity(array $seed): SpyOmsEventTimeout

return $omsEventTimeout;
}

/**
* @return void
*/
protected function clearPersistenceManagerCache(): void
{
$stateCacheProperty = new ReflectionProperty(PersistenceManager::class, 'stateCache');
$stateCacheProperty->setAccessible(true);
$stateCacheProperty->setValue([]);
$processCacheProperty = new ReflectionProperty(PersistenceManager::class, 'processCache');
$processCacheProperty->setAccessible(true);
$processCacheProperty->setValue([]);
}
}

0 comments on commit d6cc889

Please sign in to comment.