2020-06-16 08:22:47 +00:00
|
|
|
<?php
|
|
|
|
|
|
2024-04-14 13:48:14 +00:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
namespace Benzine\Workers;
|
|
|
|
|
|
|
|
|
|
use Benzine\Services\EnvironmentService;
|
2020-06-19 07:53:59 +00:00
|
|
|
use Benzine\Services\QueueService;
|
2020-06-18 17:24:31 +00:00
|
|
|
use Monolog\Logger;
|
2020-06-16 08:22:47 +00:00
|
|
|
|
|
|
|
|
abstract class AbstractQueueWorker extends AbstractWorker
|
|
|
|
|
{
|
|
|
|
|
protected QueueService $queueService;
|
|
|
|
|
|
2024-04-14 16:05:21 +00:00
|
|
|
/** @var ?string Name of the input redis queue */
|
2020-06-16 08:22:47 +00:00
|
|
|
protected ?string $inputQueue;
|
2022-06-19 01:19:07 +00:00
|
|
|
|
2024-04-14 16:05:21 +00:00
|
|
|
/** @var ?string[] Name of the output redis queues */
|
2020-06-16 08:22:47 +00:00
|
|
|
protected ?array $outputQueues;
|
|
|
|
|
|
2020-07-07 16:46:34 +00:00
|
|
|
protected ?array $resultItems;
|
|
|
|
|
|
2020-11-23 16:04:02 +00:00
|
|
|
protected bool $showRemainingQueueLength = true;
|
|
|
|
|
|
2020-12-05 00:45:02 +00:00
|
|
|
protected int $lastLength = -1;
|
|
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
public function __construct(
|
|
|
|
|
QueueService $queueService,
|
|
|
|
|
Logger $logger,
|
|
|
|
|
EnvironmentService $environmentService
|
|
|
|
|
) {
|
|
|
|
|
$this->queueService = $queueService;
|
|
|
|
|
parent::__construct($logger, $environmentService);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function setUp(): void
|
|
|
|
|
{
|
|
|
|
|
parent::setUp();
|
2020-07-16 22:44:44 +00:00
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
// Set default queues
|
|
|
|
|
if (!isset($this->inputQueue)) {
|
|
|
|
|
$this->inputQueue = sprintf('%s:input', $this->getClassWithoutNamespace());
|
|
|
|
|
}
|
|
|
|
|
if (!isset($this->outputQueues)) {
|
|
|
|
|
$this->outputQueues[] = sprintf('%s:output', $this->getClassWithoutNamespace());
|
|
|
|
|
}
|
2020-07-16 22:44:44 +00:00
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
$this->logger->debug(
|
|
|
|
|
sprintf(
|
2020-06-19 07:53:59 +00:00
|
|
|
'Worker %s: Listening to "%s" and outputting on %d channel(s)',
|
2020-06-16 08:22:47 +00:00
|
|
|
$this->getClassWithoutNamespace(),
|
|
|
|
|
$this->inputQueue,
|
|
|
|
|
count($this->outputQueues)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getQueueService(): QueueService
|
|
|
|
|
{
|
|
|
|
|
return $this->queueService;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setQueueService(QueueService $queueService): AbstractQueueWorker
|
|
|
|
|
{
|
|
|
|
|
$this->queueService = $queueService;
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getInputQueue(): string
|
|
|
|
|
{
|
|
|
|
|
return $this->inputQueue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setInputQueue(string $inputQueue): AbstractQueueWorker
|
|
|
|
|
{
|
|
|
|
|
$this->inputQueue = $inputQueue;
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return string[]
|
|
|
|
|
*/
|
|
|
|
|
public function getOutputQueues(): array
|
|
|
|
|
{
|
|
|
|
|
return $this->outputQueues;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param string[] $outputQueues
|
|
|
|
|
*/
|
|
|
|
|
public function setOutputQueues(array $outputQueues): AbstractQueueWorker
|
|
|
|
|
{
|
|
|
|
|
$this->outputQueues = $outputQueues;
|
|
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function iterate(): bool
|
|
|
|
|
{
|
|
|
|
|
$queueLength = $this->queueService->getQueueLength($this->inputQueue);
|
2020-12-05 00:45:02 +00:00
|
|
|
if ($this->showRemainingQueueLength && $queueLength != $this->lastLength) {
|
2020-11-23 16:04:02 +00:00
|
|
|
$this->logger->debug(sprintf(
|
|
|
|
|
'Queue %s Length: %d',
|
|
|
|
|
$this->inputQueue,
|
|
|
|
|
$queueLength
|
|
|
|
|
));
|
2020-12-05 00:45:02 +00:00
|
|
|
$this->lastLength = $queueLength;
|
2020-11-23 16:04:02 +00:00
|
|
|
}
|
2020-06-16 08:22:47 +00:00
|
|
|
|
2021-01-09 12:02:44 +00:00
|
|
|
if ($this->stopOnZero && 0 == $queueLength) {
|
2020-06-16 08:22:47 +00:00
|
|
|
$this->logger->warning('--stop-on-zero is set, and the queue length is zero! Stopping!');
|
2021-01-22 04:20:21 +00:00
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($queueLength <= 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-14 13:48:14 +00:00
|
|
|
$items = $this->queueService->pop($this->inputQueue);
|
2020-07-07 16:46:34 +00:00
|
|
|
$this->resultItems = [];
|
2020-07-16 22:44:44 +00:00
|
|
|
|
2020-11-22 17:10:03 +00:00
|
|
|
// If there are no items popped, return fast.
|
2020-11-22 17:12:08 +00:00
|
|
|
if (count($items) == 0) {
|
2020-11-22 17:10:03 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
foreach ($items as $item) {
|
2020-07-17 07:23:02 +00:00
|
|
|
try {
|
|
|
|
|
$processResults = $this->process($item);
|
2020-11-22 17:11:48 +00:00
|
|
|
if (is_array($processResults)) {
|
|
|
|
|
foreach ($processResults as $processResult) {
|
|
|
|
|
$this->resultItems[] = $processResult;
|
|
|
|
|
}
|
|
|
|
|
} elseif (null !== $processResults) {
|
|
|
|
|
$this->resultItems[] = $processResults;
|
|
|
|
|
}
|
2020-07-17 07:23:02 +00:00
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$this->returnToInputQueue($item);
|
|
|
|
|
|
|
|
|
|
$this->logger->error(
|
2020-07-17 07:35:39 +00:00
|
|
|
sprintf(
|
|
|
|
|
'Exception encountered while processing message queue: %s',
|
|
|
|
|
$e->getMessage()
|
|
|
|
|
),
|
2020-07-17 07:23:02 +00:00
|
|
|
[
|
2024-04-14 13:48:14 +00:00
|
|
|
'file' => $e->getFile(),
|
|
|
|
|
'line' => $e->getLine(),
|
|
|
|
|
'code' => $e->getCode(),
|
2020-07-17 07:23:02 +00:00
|
|
|
'trace' => array_slice($e->getTrace(), 0, 5),
|
|
|
|
|
]
|
|
|
|
|
);
|
2020-06-16 08:22:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-16 22:44:44 +00:00
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
foreach ($this->outputQueues as $outputQueue) {
|
2020-07-07 16:46:34 +00:00
|
|
|
$this->queueService->push($outputQueue, $this->resultItems);
|
2020-06-16 08:22:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-07 16:46:34 +00:00
|
|
|
public function getResultItems(): ?array
|
|
|
|
|
{
|
|
|
|
|
return $this->resultItems;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-16 08:22:47 +00:00
|
|
|
/**
|
|
|
|
|
* Send work item back to the queue it came from.
|
|
|
|
|
*/
|
|
|
|
|
protected function returnToInputQueue(WorkerWorkItem $item): void
|
|
|
|
|
{
|
|
|
|
|
$this->queueService->push($this->inputQueue, [$item]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function sendToSuccessQueues(WorkerWorkItem $item): int
|
|
|
|
|
{
|
|
|
|
|
$queuedItems = 0;
|
|
|
|
|
foreach ($this->outputQueues as $outputQueue) {
|
|
|
|
|
$queuedItems += $this->queueService->push($outputQueue, [$item]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $queuedItems;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function sendToFailureQueue(WorkerWorkItem $item): void
|
|
|
|
|
{
|
|
|
|
|
$this->queueService->push($this->getFailureQueue(), [$item]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getFailureQueue(): string
|
|
|
|
|
{
|
|
|
|
|
return sprintf('%s:failures', $this->inputQueue);
|
|
|
|
|
}
|
2020-06-24 17:49:56 +00:00
|
|
|
|
2020-07-16 23:12:24 +00:00
|
|
|
/**
|
2020-07-21 01:02:52 +00:00
|
|
|
* @return null|WorkerWorkItem|WorkerWorkItem[]
|
2020-07-16 23:12:24 +00:00
|
|
|
*/
|
|
|
|
|
abstract protected function process(WorkerWorkItem $item);
|
2020-06-16 08:22:47 +00:00
|
|
|
}
|