feat: add a lock on domain update

This commit is contained in:
Maël Gangloff 2025-11-09 20:03:52 +01:00
parent d236d12cec
commit aebc90d34b
No known key found for this signature in database
GPG Key ID: 11FDC81C24A7F629
2 changed files with 39 additions and 1 deletions

View File

@ -7,7 +7,7 @@ final class UpdateDomain
public function __construct( public function __construct(
public string $ldhName, public string $ldhName,
public ?string $watchlistToken, public ?string $watchlistToken,
public bool $onlyNew = false, public bool $onlyNew,
) { ) {
} }
} }

View File

@ -20,6 +20,9 @@ use App\Service\ChatNotificationService;
use App\Service\RDAPService; use App\Service\RDAPService;
use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\OptimisticLockException;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Lock\Key;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\SharedLockInterface;
use Symfony\Component\Mailer\Exception\TransportExceptionInterface; use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Attribute\AsMessageHandler;
@ -49,6 +52,7 @@ final readonly class UpdateDomainHandler
private WatchlistRepository $watchlistRepository, private WatchlistRepository $watchlistRepository,
private DomainRepository $domainRepository, private DomainRepository $domainRepository,
private LoggerInterface $logger, private LoggerInterface $logger,
private LockFactory $lockFactory,
) { ) {
$this->sender = new Address($mailerSenderEmail, $mailerSenderName); $this->sender = new Address($mailerSenderEmail, $mailerSenderName);
} }
@ -68,6 +72,7 @@ final readonly class UpdateDomainHandler
*/ */
public function __invoke(UpdateDomain $message): void public function __invoke(UpdateDomain $message): void
{ {
/** @var ?Domain $domain */
$domain = $this->domainRepository->findOneBy(['ldhName' => $message->ldhName]); $domain = $this->domainRepository->findOneBy(['ldhName' => $message->ldhName]);
if (null !== $domain && $message->onlyNew) { if (null !== $domain && $message->onlyNew) {
@ -79,12 +84,24 @@ final readonly class UpdateDomainHandler
} }
if (null === $domain) { if (null === $domain) {
$lock = $this->createDomainLock($message->ldhName);
if (!$lock->acquire()) {
$this->logger->notice('Update of this domain name is locked because it is already in progress', [
'ldhName' => $message->ldhName,
]);
return;
}
try { try {
$this->RDAPService->registerDomain($message->ldhName); $this->RDAPService->registerDomain($message->ldhName);
} catch (TldNotSupportedException|MalformedDomainException $exception) { } catch (TldNotSupportedException|MalformedDomainException $exception) {
throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception); throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception);
} catch (UnknownRdapServerException|DomainNotFoundException) { } catch (UnknownRdapServerException|DomainNotFoundException) {
return; return;
} finally {
$lock->release();
} }
return; return;
@ -124,6 +141,16 @@ final readonly class UpdateDomainHandler
$updatedAt = $domain->getUpdatedAt(); $updatedAt = $domain->getUpdatedAt();
$deleted = $domain->getDeleted(); $deleted = $domain->getDeleted();
$lock = $this->createDomainLock($message->ldhName);
if (!$lock->acquire()) {
$this->logger->notice('Update of this domain name is locked because it is already in progress', [
'ldhName' => $message->ldhName,
]);
return;
}
try { try {
/* /*
* Domain name update * Domain name update
@ -158,6 +185,17 @@ final readonly class UpdateDomainHandler
throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception); throw new UnrecoverableMessageHandlingException($exception->getMessage(), 0, $exception);
} catch (UnknownRdapServerException) { } catch (UnknownRdapServerException) {
return; return;
} finally {
$lock->release();
} }
} }
private function createDomainLock(string $ldhName): SharedLockInterface
{
return $this->lockFactory->createLockFromKey(
new Key('domain_update.'.$ldhName),
ttl: 600,
autoRelease: false
);
}
} }