diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 56aceed..58e1b5c 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -63,6 +63,13 @@ export default defineConfig({ content: 'Domain Watchdog, RDAP, WHOIS, domain monitoring, domain history, domain expiration, domain tracker' }, }, + { + tag: 'meta', + attrs: { + name: 'author', + content: 'Maƫl Gangloff' + }, + }, { tag: 'meta', attrs: {name: 'twitter:card', content: 'summary'}, diff --git a/src/Entity/Domain.php b/src/Entity/Domain.php index 192cfd9..e39372c 100644 --- a/src/Entity/Domain.php +++ b/src/Entity/Domain.php @@ -68,7 +68,7 @@ use Symfony\Component\Serializer\Attribute\SerializedName; ], ], parameters: [ - 'forced' => new QueryParameter(schema: ['type' => 'boolean'], description: 'Force an RDAP request', required: false), + 'forced' => new QueryParameter(schema: ['type' => 'boolean'], description: 'Force an RDAP request. If an update is already in progress, this parameter is ignored and the stored domain is returned.', required: false), ], ), ], diff --git a/src/State/AutoRegisterDomainProvider.php b/src/State/AutoRegisterDomainProvider.php index 5387160..27a1ebb 100644 --- a/src/State/AutoRegisterDomainProvider.php +++ b/src/State/AutoRegisterDomainProvider.php @@ -22,6 +22,9 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\LockFactory; +use Symfony\Component\Lock\SharedLockInterface; use Symfony\Component\Messenger\Exception\ExceptionInterface; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\RateLimiter\RateLimiterFactory; @@ -44,6 +47,7 @@ readonly class AutoRegisterDomainProvider implements ProviderInterface private MessageBusInterface $bus, private RequestStack $requestStack, private EntityManagerInterface $em, + private LockFactory $lockFactory, ) { } @@ -100,6 +104,16 @@ readonly class AutoRegisterDomainProvider implements ProviderInterface } } + $lock = $this->createDomainLock($idnDomain); + + if (!$lock->acquire() && null !== $domain) { + $this->logger->notice('Update of this domain name is locked because it is already in progress', [ + 'ldhName' => $idnDomain, + ]); + + return $domain; + } + $updatedAt = null === $domain ? new \DateTimeImmutable('now') : $domain->getUpdatedAt(); try { @@ -124,6 +138,8 @@ readonly class AutoRegisterDomainProvider implements ProviderInterface $this->em->flush(); return $domain->setExpiresInDays($this->RDAPService->getExpiresInDays($domain)); + } finally { + $lock->release(); } $randomizer = new Randomizer(); @@ -136,4 +152,13 @@ readonly class AutoRegisterDomainProvider implements ProviderInterface return $domain->setExpiresInDays($this->RDAPService->getExpiresInDays($domain)); } + + private function createDomainLock(string $ldhName): SharedLockInterface + { + return $this->lockFactory->createLockFromKey( + new Key('domain_update.'.$ldhName), + ttl: 600, + autoRelease: false + ); + } }