Updated NotifyVisitToWebHooks so that it waits for all requests to finish

This commit is contained in:
Alejandro Celaya 2019-12-27 17:07:20 +01:00
parent 562b0a0868
commit 21a3d4b66b
4 changed files with 40 additions and 15 deletions

View file

@ -40,6 +40,7 @@ return [
'em',
'Logger_Shlink',
'config.url_shortener.visits_webhooks',
'config.url_shortener.domain',
],
],

View file

@ -61,6 +61,11 @@ class Visit extends AbstractEntity implements JsonSerializable
return ! empty($this->remoteAddr);
}
public function getShortUrl(): ShortUrl
{
return $this->shortUrl;
}
public function getVisitLocation(): VisitLocationInterface
{
return $this->visitLocation ?? new UnknownVisitLocation();

View file

@ -10,8 +10,12 @@ use GuzzleHttp\ClientInterface;
use GuzzleHttp\RequestOptions;
use Psr\Log\LoggerInterface;
use Shlinkio\Shlink\Core\Entity\Visit;
use Shlinkio\Shlink\Core\Transformer\ShortUrlDataTransformer;
use Throwable;
use function Functional\map;
use function Functional\partial_left;
use function GuzzleHttp\Promise\settle;
class NotifyVisitToWebHooks
{
@ -23,17 +27,21 @@ class NotifyVisitToWebHooks
private $logger;
/** @var array */
private $webhooks;
/** @var ShortUrlDataTransformer */
private $transformer;
public function __construct(
ClientInterface $httpClient,
EntityManagerInterface $em,
LoggerInterface $logger,
array $webhooks
array $webhooks,
array $domainConfig
) {
$this->httpClient = $httpClient;
$this->em = $em;
$this->logger = $logger;
$this->webhooks = $webhooks;
$this->transformer = new ShortUrlDataTransformer($domainConfig);
}
public function __invoke(ShortUrlLocated $shortUrlLocated): void
@ -51,17 +59,25 @@ class NotifyVisitToWebHooks
$requestOptions = [
RequestOptions::TIMEOUT => 10,
RequestOptions::JSON => $visit->jsonSerialize(),
RequestOptions::JSON => [
'shortUrl' => $this->transformer->transform($visit->getShortUrl(), false),
'visit' => $visit->jsonSerialize(),
],
];
$requestPromises = map($this->webhooks, function (string $webhook) use ($requestOptions, $visitId) {
$logWebhookWarning = function (string $webhook, Throwable $e) use ($visitId): void {
$this->logger->warning('Failed to notify visit with id "{visitId}" to webhook "{webhook}". {e}', [
'visitId' => $visitId,
'webhook' => $webhook,
'e' => $e,
]);
};
$requestPromises = map($this->webhooks, function (string $webhook) use ($requestOptions, $logWebhookWarning) {
$promise = $this->httpClient->requestAsync(RequestMethodInterface::METHOD_POST, $webhook, $requestOptions);
return $promise->otherwise(function () use ($webhook, $visitId) {
// Log failures
$this->logger->warning('Failed to notify visit with id "{visitId}" to "{webhook}" webhook', [
'visitId' => $visitId,
'webhook' => $webhook,
]);
});
return $promise->otherwise(partial_left($logWebhookWarning, $webhook));
});
// Wait for all the promises to finish, ignoring rejections, as in those cases we only want to log the error.
settle($requestPromises)->wait();
}
}

View file

@ -23,11 +23,11 @@ class ShortUrlDataTransformer implements DataTransformerInterface
/**
* @param ShortUrl $shortUrl
*/
public function transform($shortUrl): array
public function transform($shortUrl, bool $includeDeprecated = true): array
{
$longUrl = $shortUrl->getLongUrl();
return [
$rawData = [
'shortCode' => $shortUrl->getShortCode(),
'shortUrl' => $shortUrl->toString($this->domainConfig),
'longUrl' => $longUrl,
@ -35,10 +35,13 @@ class ShortUrlDataTransformer implements DataTransformerInterface
'visitsCount' => $shortUrl->getVisitsCount(),
'tags' => invoke($shortUrl->getTags(), '__toString'),
'meta' => $this->buildMeta($shortUrl),
// Deprecated
'originalUrl' => $longUrl,
];
if ($includeDeprecated) {
$rawData['originalUrl'] = $longUrl;
}
return $rawData;
}
private function buildMeta(ShortUrl $shortUrl): array