mirror of
https://github.com/shlinkio/shlink.git
synced 2026-03-12 01:54:41 +08:00
Created decorator for database connection closing and reopening for swoole tasks
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user