Created decorator for database connection closing and reopening for swoole tasks

This commit is contained in:
Alejandro Celaya
2020-04-11 18:00:29 +02:00
parent 3ee5853b32
commit f915b97606
10 changed files with 204 additions and 40 deletions

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\EventDispatcher;
use Shlinkio\Shlink\Common\Doctrine\ReopeningEntityManagerInterface;
class CloseDbConnectionEventListener
{
private ReopeningEntityManagerInterface $em;
/** @var callable */
private $wrapped;
public function __construct(ReopeningEntityManagerInterface $em, callable $wrapped)
{
$this->em = $em;
$this->wrapped = $wrapped;
}
public function __invoke(object $event): void
{
$this->em->open();
try {
($this->wrapped)($event);
} finally {
$this->em->getConnection()->close();
$this->em->clear();
}
}
}

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace Shlinkio\Shlink\Core\EventDispatcher;
use Psr\Container\ContainerInterface;
use Shlinkio\Shlink\Common\Doctrine\ReopeningEntityManagerInterface;
class CloseDbConnectionEventListenerDelegator
{
public function __invoke(
ContainerInterface $container,
string $name,
callable $callback
): CloseDbConnectionEventListener {
/** @var callable $wrapped */
$wrapped = $callback();
/** @var ReopeningEntityManagerInterface $em */
$em = $container->get('em');
return new CloseDbConnectionEventListener($em, $wrapped);
}
}

View File

@@ -9,7 +9,6 @@ use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\CLI\Exception\GeolocationDbUpdateFailedException;
use Shlinkio\Shlink\CLI\Util\GeolocationDbUpdaterInterface;
use Shlinkio\Shlink\Common\Doctrine\ReopeningEntityManager;
use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Entity\VisitLocation;
use Shlinkio\Shlink\IpGeolocation\Exception\WrongIpException;
@@ -42,35 +41,22 @@ class LocateShortUrlVisit
public function __invoke(ShortUrlVisited $shortUrlVisited): void
{
// FIXME Temporarily handling DB connection reset here to fix https://github.com/shlinkio/shlink/issues/717
// Remove when https://github.com/shlinkio/shlink-event-dispatcher/issues/23 is implemented
if ($this->em instanceof ReopeningEntityManager) {
$this->em->open();
}
$visitId = $shortUrlVisited->visitId();
try {
/** @var Visit|null $visit */
$visit = $this->em->find(Visit::class, $visitId);
if ($visit === null) {
$this->logger->warning('Tried to locate visit with id "{visitId}", but it does not exist.', [
'visitId' => $visitId,
]);
return;
}
if ($this->downloadOrUpdateGeoLiteDb($visitId)) {
$this->locateVisit($visitId, $shortUrlVisited->originalIpAddress(), $visit);
}
$this->eventDispatcher->dispatch(new VisitLocated($visitId));
} finally {
// FIXME Temporarily handling DB connection reset here to fix https://github.com/shlinkio/shlink/issues/717
// Remove when https://github.com/shlinkio/shlink-event-dispatcher/issues/23 is implemented
$this->em->getConnection()->close();
$this->em->clear();
/** @var Visit|null $visit */
$visit = $this->em->find(Visit::class, $visitId);
if ($visit === null) {
$this->logger->warning('Tried to locate visit with id "{visitId}", but it does not exist.', [
'visitId' => $visitId,
]);
return;
}
if ($this->downloadOrUpdateGeoLiteDb($visitId)) {
$this->locateVisit($visitId, $shortUrlVisited->originalIpAddress(), $visit);
}
$this->eventDispatcher->dispatch(new VisitLocated($visitId));
}
private function downloadOrUpdateGeoLiteDb(string $visitId): bool

View File

@@ -9,6 +9,7 @@ use Doctrine\ORM\EntityManagerInterface;
use Fig\Http\Message\RequestMethodInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\RequestOptions;
use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Core\Entity\Visit;
@@ -89,12 +90,14 @@ class NotifyVisitToWebHooks
*/
private function performRequests(array $requestOptions, string $visitId): array
{
return map($this->webhooks, function (string $webhook) use ($requestOptions, $visitId) {
$promise = $this->httpClient->requestAsync(RequestMethodInterface::METHOD_POST, $webhook, $requestOptions);
return $promise->otherwise(
partial_left(Closure::fromCallable([$this, 'logWebhookFailure']), $webhook, $visitId),
);
});
$logWebhookFailure = Closure::fromCallable([$this, 'logWebhookFailure']);
return map(
$this->webhooks,
fn (string $webhook): PromiseInterface => $this->httpClient
->requestAsync(RequestMethodInterface::METHOD_POST, $webhook, $requestOptions)
->otherwise(partial_left($logWebhookFailure, $webhook, $visitId)),
);
}
private function logWebhookFailure(string $webhook, string $visitId, Throwable $e): void