src/WebBundle/Scenario/SendToOneCQueueScenario.php line 45

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace WebBundle\Scenario;
  4. use Psr\Cache\CacheItemInterface;
  5. use Symfony\Component\Cache\Adapter\AdapterInterface;
  6. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  7. use WebBundle\Dto\OneCRequestsDto;
  8. /**
  9.  * Сценарий генерирует псевдо-очередь на редисе.
  10.  * - создаётся uuid для запроса;
  11.  * - если нет записи с orderHash добавляется структура с первым элементом (uuid) и ставится статус в обработке;
  12.  * - обработка пропускает дальше;
  13.  * - при поступлении нового запроса (2) - он ставится вторым и обработка становится в режим ожидания (TIME_FOR_DELAY);
  14.  * - если пришел следующий (3) запрос (первый ещё не кончился) - он затирает последний;
  15.  * - запрос 2 оживает, не видит себя на обоих местах и умирает;
  16.  * ... для остальных запросов также
  17.  * - первый сообщает, что закончил и удаляется ставя идущий за ним на первое место;
  18.  * - когда оживает этот запрос - он пропускает свою обработку дальше;
  19.  *
  20.  * При возникновении какой-либо ошибки (напр на коннекте редиса) - просто пропускаем задержку очереди
  21.  */
  22. class SendToOneCQueueScenario
  23. {
  24.     // время, через которое проснётся следующий запрос и начнёт проверять
  25.     public const TIME_FOR_DELAY_IN_SEC 3;
  26.     // максимально допустимое время на обработку, если запрос идёт дольше - можем запускать следующий
  27.     public const TIME_FOR_CRUSH_IN_SEC 100;
  28.     public const MAX_COUNT_FOR_WAIT 35;
  29.     public const CACHE_KEY 'onec';
  30.     private AdapterInterface $cacheAdapter;
  31.     private ?CacheItemInterface $cacheItem null;
  32.     private string $cacheKey;
  33.     protected string $uuidRequest;
  34.     public function __construct(AdapterInterface $cacheAdapterstring $orderHashstring $typeOfFunc)
  35.     {
  36.         $this->cacheAdapter $cacheAdapter;
  37.         $this->cacheKey self::CACHE_KEY $typeOfFunc $orderHash;
  38.         $this->uuidRequest uniqid($orderHashtrue);
  39.         $this->getFirstStructData();
  40.     }
  41.     public function checkForStart(): void
  42.     {
  43.         if (!$this->initCacheItem()) {
  44.             return;
  45.         }
  46.         $data $this->getNormalizeStruct();
  47.         if ($this->isFirstRequest($data)) {
  48.             return;
  49.         }
  50.         $maxCountForWait self::MAX_COUNT_FOR_WAIT;
  51.         while (!$this->checkStruct($data)) {
  52.             if ($maxCountForWait <= 0) {
  53.                 break;
  54.             }
  55.             $this->getSleep();
  56.             $maxCountForWait--;
  57.             if (!$this->initCacheItem()) {
  58.                 return;
  59.             }
  60.             $data $this->getNormalizeStruct();
  61.         }
  62.         $this->setFirstRequest($data$this->uuidRequest);
  63.         $data->setSecondRequest(null);
  64.         $this->saveToCache($data);
  65.     }
  66.     public function setFinish(): void
  67.     {
  68.         if (!$this->initCacheItem()) {
  69.             return;
  70.         }
  71.         if (!$this->cacheItem->isHit()) {
  72.             return;
  73.         }
  74.         /** @var OneCRequestsDto $data */
  75.         $data $this->cacheItem->get();
  76.         if (null === $data) {
  77.             return;
  78.         }
  79.         if (null === $data->secondRequest
  80.             || $data->secondRequest === $this->uuidRequest
  81.         ) {
  82.             $this->saveToCache($data0);
  83.             return;
  84.         }
  85.         $this->setFirstRequest($data$data->secondRequest);
  86.         $data->setSecondRequest(null);
  87.         $this->saveToCache($data);
  88.     }
  89.     private function getFirstStructData(): void
  90.     {
  91.         if (!$this->initCacheItem()) {
  92.             return;
  93.         }
  94.         $data $this->getNormalizeStruct();
  95.         if ($data->firstRequest !== $this->uuidRequest) {
  96.             $data->setSecondRequest($this->uuidRequest);
  97.         }
  98.         $this->saveToCache($data);
  99.     }
  100.     private function getNormalizeStruct(): OneCRequestsDto
  101.     {
  102.         $data null;
  103.         if ($this->cacheItem->isHit()) {
  104.             /** @var OneCRequestsDto $data */
  105.             $data $this->cacheItem->get();
  106.         }
  107.         if (null === $data) {
  108.             $data = new OneCRequestsDto();
  109.         }
  110.         $this->normalizeStruct($data);
  111.         return $data;
  112.     }
  113.     private function normalizeStruct(OneCRequestsDto $data): void
  114.     {
  115.         if (null === $data->firstRequest || $this->isFirstRequestExpired($data)) {
  116.             $this->setFirstRequest($data$this->uuidRequest);
  117.             $data->setSecondRequest(null);
  118.         }
  119.         if ($data->firstRequest === $data->secondRequest) {
  120.             $data->setSecondRequest(null);
  121.         }
  122.     }
  123.     protected function getSleep(): void
  124.     {
  125.         sleep(self::TIME_FOR_DELAY_IN_SEC);
  126.     }
  127.     private function saveToCache(OneCRequestsDto $dataint $timeForExpired self::TIME_FOR_CRUSH_IN_SEC 2): void
  128.     {
  129.         $this->cacheItem->expiresAfter((int) $timeForExpired);
  130.         $this->cacheItem->set($data);
  131.         $this->cacheAdapter->save($this->cacheItem);
  132.     }
  133.     private function checkStruct(OneCRequestsDto $data): bool
  134.     {
  135.         if ($data->firstRequest === $this->uuidRequest) {
  136.             return true;
  137.         }
  138.         if ($this->isFirstRequestExpired($data)) {
  139.             return true;
  140.         }
  141.         if ($data->secondRequest === $this->uuidRequest) {
  142.             return false;
  143.         }
  144.         $this->terminate();
  145.         return false// %-))
  146.     }
  147.     protected function terminate(): void
  148.     {
  149.         die();
  150.     }
  151.     protected function getCurrentTime(): int
  152.     {
  153.         return time();
  154.     }
  155.     private function initCacheItem(): bool
  156.     {
  157.         try {
  158.             $this->cacheItem $this->cacheAdapter->getItem($this->cacheKey);
  159.             return true;
  160.         } catch (InvalidArgumentException $e) {
  161.             return false;
  162.         }
  163.     }
  164.     private function setFirstRequest(OneCRequestsDto $data, ?string $request)
  165.     {
  166.         $data->setFirstRequest($request);
  167.         $data->setTimestampFirstRequest($this->getCurrentTime());
  168.     }
  169.     private function isFirstRequest(OneCRequestsDto $data): bool
  170.     {
  171.         return $data->firstRequest === $this->uuidRequest;
  172.     }
  173.     private function isFirstRequestExpired(OneCRequestsDto $data): bool
  174.     {
  175.         return $this->getCurrentTime() >= $data->timestampFirstRequest + static::TIME_FOR_CRUSH_IN_SEC;
  176.     }
  177. }