Skip to content

Commit 0c0b0df

Browse files
authored
Skip poll messages on deletions for configured registrars (#2613)
See b/379331882 for more details
1 parent 304f000 commit 0c0b0df

File tree

9 files changed

+87
-30
lines changed

9 files changed

+87
-30
lines changed

core/src/main/java/google/registry/config/RegistryConfig.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1743,6 +1743,17 @@ public static ImmutableSet<String> getTieredPricingPromotionRegistrarIds() {
17431743
CONFIG_SETTINGS.get().registryPolicy.tieredPricingPromotionRegistrarIds);
17441744
}
17451745

1746+
/**
1747+
* Set of registrars for which we do not send poll messages on standard domain deletion.
1748+
*
1749+
* <p>For these registrars we won't send a poll message in order to avoid database contention. See
1750+
* b/379331882 for more details.
1751+
*/
1752+
public static ImmutableSet<String> getNoPollMessageOnDeletionRegistrarIds() {
1753+
return ImmutableSet.copyOf(
1754+
CONFIG_SETTINGS.get().registryPolicy.noPollMessageOnDeletionRegistrarIds);
1755+
}
1756+
17461757
/**
17471758
* Memoizes loading of the {@link RegistryConfigSettings} POJO.
17481759
*

core/src/main/java/google/registry/config/RegistryConfigSettings.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public static class RegistryPolicy {
115115
public boolean requireSslCertificates;
116116
public double sunriseDomainCreateDiscount;
117117
public Set<String> tieredPricingPromotionRegistrarIds;
118+
public Set<String> noPollMessageOnDeletionRegistrarIds;
118119
}
119120

120121
/** Configuration for Hibernate. */

core/src/main/java/google/registry/config/files/default-config.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ registryPolicy:
220220
# In addition, we will return the non-promotional (i.e. incorrect) price on
221221
# domain create requests.
222222
tieredPricingPromotionRegistrarIds: []
223+
# List of registrars for which we won't send poll message on standard domain
224+
# deletions.
225+
noPollMessageOnDeletionRegistrarIds: []
223226

224227
hibernate:
225228
# If set to false, calls to tm().transact() cannot be nested. If set to true,

core/src/main/java/google/registry/config/files/nomulus-config-unittest.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ registryPolicy:
1111
Line 2 is this 1.
1212
tieredPricingPromotionRegistrarIds:
1313
- NewRegistrar
14+
noPollMessageOnDeletionRegistrarIds:
15+
- NewRegistrar
1416

1517
caching:
1618
singletonCacheRefreshSeconds: 0

core/src/main/java/google/registry/flows/domain/DomainDeleteFlow.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
import com.google.common.collect.ImmutableSet;
4545
import com.google.common.collect.ImmutableSortedSet;
4646
import com.google.common.collect.Sets;
47+
import com.google.common.flogger.FluentLogger;
4748
import google.registry.batch.AsyncTaskEnqueuer;
49+
import google.registry.config.RegistryConfig;
4850
import google.registry.flows.EppException;
4951
import google.registry.flows.EppException.AssociationProhibitsOperationException;
5052
import google.registry.flows.ExtensionManager;
@@ -117,6 +119,8 @@
117119
@ReportingSpec(ActivityReportField.DOMAIN_DELETE)
118120
public final class DomainDeleteFlow implements MutatingFlow {
119121

122+
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
123+
120124
private static final ImmutableSet<StatusValue> DISALLOWED_STATUSES = ImmutableSet.of(
121125
StatusValue.CLIENT_DELETE_PROHIBITED,
122126
StatusValue.PENDING_DELETE,
@@ -212,10 +216,17 @@ public EppResponse run() throws EppException {
212216
// superuser (i.e. the registrar didn't request this delete and thus should be notified even if
213217
// it is synchronous).
214218
if (durationUntilDelete.isLongerThan(Duration.ZERO) || isSuperuser) {
215-
PollMessage.OneTime deletePollMessage =
216-
createDeletePollMessage(existingDomain, domainHistoryId, deletionTime);
217-
entitiesToSave.add(deletePollMessage);
218-
builder.setDeletePollMessage(deletePollMessage.createVKey());
219+
if (RegistryConfig.getNoPollMessageOnDeletionRegistrarIds()
220+
.contains(existingDomain.getCurrentSponsorRegistrarId())) {
221+
logger.atInfo().log(
222+
"Skipping poll message on domain deletion for registrar %s due to configuration",
223+
existingDomain.getCurrentSponsorRegistrarId());
224+
} else {
225+
PollMessage.OneTime deletePollMessage =
226+
createDeletePollMessage(existingDomain, domainHistoryId, deletionTime);
227+
entitiesToSave.add(deletePollMessage);
228+
builder.setDeletePollMessage(deletePollMessage.createVKey());
229+
}
219230
}
220231

221232
// Send a second poll message immediately if the domain is being deleted asynchronously by a

core/src/main/java/google/registry/flows/domain/DomainRestoreRequestFlow.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ public EppResponse run() throws EppException {
183183
DomainHistory domainHistory = buildDomainHistory(newDomain, now);
184184
entitiesToSave.add(newDomain, domainHistory, autorenewEvent, autorenewPollMessage);
185185
tm().putAll(entitiesToSave.build());
186-
tm().delete(existingDomain.getDeletePollMessage());
186+
if (existingDomain.getDeletePollMessage() != null) {
187+
tm().delete(existingDomain.getDeletePollMessage());
188+
}
187189
requestDomainDnsRefresh(existingDomain.getDomainName());
188190
return responseBuilder
189191
.setExtensions(createResponseExtensions(feesAndCredits, feeUpdate, isExpired))

core/src/test/java/google/registry/flows/domain/DomainDeleteFlowTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,4 +1247,15 @@ void testSuccess_freeCreation_deletionDuringGracePeriod() throws Exception {
12471247
clock.advanceOneMilli();
12481248
runFlowAssertResponse(loadFile("domain_delete_response_fee_free_grace.xml"));
12491249
}
1250+
1251+
@Test
1252+
void testSuccess_skipsPollMessage_whenConfigured() throws Exception {
1253+
setUpSuccessfulTest();
1254+
domain =
1255+
persistResource(
1256+
domain.asBuilder().setPersistedCurrentSponsorRegistrarId("NewRegistrar").build());
1257+
setRegistrarIdForFlow("NewRegistrar");
1258+
runFlowAssertResponse(loadFile("domain_delete_response_pending.xml"));
1259+
assertPollMessages();
1260+
}
12501261
}

core/src/test/java/google/registry/flows/domain/DomainRestoreRequestFlowTest.java

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
7575
import google.registry.model.reporting.HistoryEntry;
7676
import google.registry.model.tld.Tld;
77+
import google.registry.persistence.VKey;
7778
import google.registry.testing.DatabaseHelper;
7879
import java.util.Map;
7980
import java.util.Optional;
@@ -103,12 +104,12 @@ void initDomainTest() {
103104
setEppInput("domain_update_restore_request.xml", ImmutableMap.of("DOMAIN", "example.tld"));
104105
}
105106

106-
void persistPendingDeleteDomain() throws Exception {
107+
Domain persistPendingDeleteDomain() throws Exception {
107108
// The domain is now past what had been its expiration date at the time of deletion.
108-
persistPendingDeleteDomain(clock.nowUtc().minusDays(5));
109+
return persistPendingDeleteDomain(clock.nowUtc().minusDays(5));
109110
}
110111

111-
void persistPendingDeleteDomain(DateTime expirationTime) throws Exception {
112+
Domain persistPendingDeleteDomain(DateTime expirationTime) throws Exception {
112113
Domain domain = persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand()));
113114
HistoryEntry historyEntry =
114115
persistResource(
@@ -118,29 +119,31 @@ void persistPendingDeleteDomain(DateTime expirationTime) throws Exception {
118119
.setRegistrarId(domain.getCurrentSponsorRegistrarId())
119120
.setDomain(domain)
120121
.build());
121-
persistResource(
122-
domain
123-
.asBuilder()
124-
.setRegistrationExpirationTime(expirationTime)
125-
.setDeletionTime(clock.nowUtc().plusDays(35))
126-
.addGracePeriod(
127-
GracePeriod.create(
128-
GracePeriodStatus.REDEMPTION,
129-
domain.getRepoId(),
130-
clock.nowUtc().plusDays(1),
131-
"TheRegistrar",
132-
null))
133-
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
134-
.setDeletePollMessage(
135-
persistResource(
136-
new PollMessage.OneTime.Builder()
137-
.setRegistrarId("TheRegistrar")
138-
.setEventTime(clock.nowUtc().plusDays(5))
139-
.setHistoryEntry(historyEntry)
140-
.build())
141-
.createVKey())
142-
.build());
122+
domain =
123+
persistResource(
124+
domain
125+
.asBuilder()
126+
.setRegistrationExpirationTime(expirationTime)
127+
.setDeletionTime(clock.nowUtc().plusDays(35))
128+
.addGracePeriod(
129+
GracePeriod.create(
130+
GracePeriodStatus.REDEMPTION,
131+
domain.getRepoId(),
132+
clock.nowUtc().plusDays(1),
133+
"TheRegistrar",
134+
null))
135+
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
136+
.setDeletePollMessage(
137+
persistResource(
138+
new PollMessage.OneTime.Builder()
139+
.setRegistrarId("TheRegistrar")
140+
.setEventTime(clock.nowUtc().plusDays(5))
141+
.setHistoryEntry(historyEntry)
142+
.build())
143+
.createVKey())
144+
.build());
143145
clock.advanceOneMilli();
146+
return domain;
144147
}
145148

146149
@Test
@@ -491,6 +494,15 @@ void testSuccess_superuserOverridesPremiumNameBlock() throws Exception {
491494
loadFile("domain_update_restore_request_response_premium.xml"));
492495
}
493496

497+
@Test
498+
void testSuccess_worksWithoutPollMessage() throws Exception {
499+
Domain domain = persistPendingDeleteDomain();
500+
VKey<PollMessage.OneTime> deletePollMessage = domain.getDeletePollMessage();
501+
persistResource(domain.asBuilder().setDeletePollMessage(null).build());
502+
DatabaseHelper.deleteByKey(deletePollMessage);
503+
runFlowAssertResponse(loadFile("generic_success_response.xml"));
504+
}
505+
494506
@Test
495507
void testFailure_doesNotExist() throws Exception {
496508
ResourceDoesNotExistException thrown =

core/src/test/java/google/registry/testing/DatabaseHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,10 @@ public static void deleteResource(final Object resource) {
11681168
tm().transact(() -> tm().delete(resource));
11691169
}
11701170

1171+
public static void deleteByKey(VKey<?> key) {
1172+
tm().transact(() -> tm().delete(key));
1173+
}
1174+
11711175
/** Force the create and update timestamps to get written into the resource. */
11721176
public static <R> R cloneAndSetAutoTimestamps(final R resource) {
11731177
// We have to separate the read and write operation into different transactions otherwise JPA

0 commit comments

Comments
 (0)