Job Queue

This commit is contained in:
Juan Pablo Vial
2025-05-10 12:30:35 -04:00
parent 61324f159b
commit 8b2de31e02
6 changed files with 251 additions and 0 deletions

51
app/src/Service/Job.php Normal file
View File

@ -0,0 +1,51 @@
<?php
namespace Incoviba\Service;
use PDOException;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal;
use Incoviba\Common\Implement\Exception\EmptyResult;
use Incoviba\Exception\ServiceAction\{Create,Read};
use Incoviba\Repository;
use Incoviba\Model;
class Job extends Ideal\Service
{
public function __construct(LoggerInterface $logger, protected Repository\Job $jobRepository)
{
parent::__construct($logger);
}
/**
* @param array $configuration
* @return Model\Job
* @throws Create
*/
public function add(array $configuration): Model\Job
{
try {
$job = $this->jobRepository->create(compact('configuration'));
return $this->process($this->jobRepository->save($job));
} catch (PDOException $exception) {
throw new Create(__CLASS__, $exception);
}
}
/**
* @return array
* @throws Read
*/
public function getPending(): array
{
try {
return array_merge([$this, 'process'],$this->jobRepository->fetchPending());
} catch (EmptyResult $exception) {
throw new Read(__CLASS__, $exception);
}
}
protected function process(Model\Job $job): Model\Job
{
return $job;
}
}

69
app/src/Service/Queue.php Normal file
View File

@ -0,0 +1,69 @@
<?php
namespace Incoviba\Service;
use Exception;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal;
use Incoviba\Exception\ServiceAction\{Create, Read};
use Incoviba\Service;
class Queue extends Ideal\Service
{
public function __construct(LoggerInterface $logger, protected Service\Job $jobService, Worker $defaultWorker)
{
parent::__construct($logger);
$this->register('default', $defaultWorker);
}
protected array $workers;
public function register(string $name, Worker $worker): self
{
$this->workers[strtolower($name)] = $worker;
return $this;
}
public function enqueue(array $configuration): bool
{
try {
$this->jobService->add($configuration);
return true;
} catch (Create $exception) {
$final = new Exception("Could not enqueue job", 0, $exception);
$this->logger->warning($final);
return false;
}
}
public function run(): bool
{
try {
$jobs = $this->jobService->getPending();
} catch (Read $exception) {
$final = new Exception("Could not get pending jobs", 0, $exception);
$this->logger->warning($final);
return false;
}
$status = true;
foreach ($jobs as $job) {
$type = 'default';
if (isset($job->configuration['type'])) {
$type = strtolower($job->configuration['type']);
}
if (!isset($this->workers[$type])) {
$type = 'default';
}
$worker = $this->workers[$type];
try {
$status &= $worker->run($job);
} catch (Exception $exception) {
$final = new Exception("Could not run job", 0, $exception);
$this->logger->warning($final);
$status &= false;
}
}
return $status;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace Incoviba\Service;
use Incoviba\Model;
interface Worker
{
public function execute(Model\Job $job): bool;
}

View File

@ -0,0 +1,50 @@
<?php
namespace Incoviba\Service\Worker;
use Incoviba\Common\Implement\Exception\EmptyResponse;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Client\ClientInterface;
use Psr\Log\LoggerInterface;
use Incoviba\Common\Ideal;
use Incoviba\Model;
class Request extends Ideal\Service
{
public function __construct(LoggerInterface $logger, protected ClientInterface $client)
{
parent::__construct($logger);
}
/**
* @param Model\Job $job
* @return bool
* @throws EmptyResponse
*/
public function execute(Model\Job $job): bool
{
$url = $job->configuration['url'];
$method = strtolower($job->configuration['method']);
$body = $job->configuration['body'];
try {
$response = $this->client->{$method}($url, [
'json' => $body,
]);
} catch (ClientExceptionInterface $exception) {
throw new EmptyResponse($url, $exception);
}
$statusCode = $response->getStatusCode();
if ((int) floor($statusCode / 100) !== 2) {
throw new EmptyResponse($url);
}
if ($statusCode !== 204) {
$contents = $response->getBody()->getContents();
$data = json_decode($contents, true);
if (!isset($data['success']) or !$data['success']) {
throw new EmptyResponse($url);
}
}
return true;
}
}