Skip to content

Commit 9c5510f

Browse files
authored
Add a rate limiter to remove all domain contacts action (#2838)
The maximum QPS defaults to 10, but can also be specified at runtime through use of a query-string parameter. BUG = http://b/439636188
1 parent 84884de commit 9c5510f

File tree

3 files changed

+29
-2
lines changed

3 files changed

+29
-2
lines changed

core/src/main/java/google/registry/batch/BatchModule.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@
2929
import static google.registry.request.RequestParameters.extractSetOfDatetimeParameters;
3030

3131
import com.google.common.collect.ImmutableSet;
32+
import com.google.common.util.concurrent.RateLimiter;
3233
import dagger.Module;
3334
import dagger.Provides;
3435
import google.registry.request.Parameter;
36+
import jakarta.inject.Named;
3537
import jakarta.servlet.http.HttpServletRequest;
3638
import java.util.Optional;
3739
import org.joda.time.DateTime;
@@ -137,4 +139,18 @@ static boolean provideAdvanceCursor(HttpServletRequest req) {
137139
static boolean provideIsFast(HttpServletRequest req) {
138140
return extractBooleanParameter(req, PARAM_FAST);
139141
}
142+
143+
private static final int DEFAULT_MAX_QPS = 10;
144+
145+
@Provides
146+
@Parameter("maxQps")
147+
static int provideMaxQps(HttpServletRequest req) {
148+
return extractOptionalIntParameter(req, "maxQps").orElse(DEFAULT_MAX_QPS);
149+
}
150+
151+
@Provides
152+
@Named("removeAllDomainContacts")
153+
static RateLimiter provideRemoveAllDomainContactsRateLimiter(@Parameter("maxQps") int maxQps) {
154+
return RateLimiter.create(maxQps);
155+
}
140156
}

core/src/main/java/google/registry/batch/RemoveAllDomainContactsAction.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import com.google.common.collect.ImmutableMap;
3131
import com.google.common.collect.ImmutableSet;
3232
import com.google.common.flogger.FluentLogger;
33+
import com.google.common.util.concurrent.RateLimiter;
3334
import google.registry.config.RegistryConfig.Config;
3435
import google.registry.flows.EppController;
3536
import google.registry.flows.EppRequestSource;
@@ -48,6 +49,7 @@
4849
import google.registry.request.auth.Auth;
4950
import google.registry.request.lock.LockHandler;
5051
import jakarta.inject.Inject;
52+
import jakarta.inject.Named;
5153
import java.util.List;
5254
import java.util.concurrent.Callable;
5355
import java.util.logging.Level;
@@ -79,6 +81,7 @@ public class RemoveAllDomainContactsAction implements Runnable {
7981
private final EppController eppController;
8082
private final String registryAdminClientId;
8183
private final LockHandler lockHandler;
84+
private final RateLimiter rateLimiter;
8285
private final Response response;
8386
private final String updateDomainXml;
8487
private int successes = 0;
@@ -91,10 +94,12 @@ public class RemoveAllDomainContactsAction implements Runnable {
9194
EppController eppController,
9295
@Config("registryAdminClientId") String registryAdminClientId,
9396
LockHandler lockHandler,
97+
@Named("removeAllDomainContacts") RateLimiter rateLimiter,
9498
Response response) {
9599
this.eppController = eppController;
96100
this.registryAdminClientId = registryAdminClientId;
97101
this.lockHandler = lockHandler;
102+
this.rateLimiter = rateLimiter;
98103
this.response = response;
99104
this.updateDomainXml =
100105
readResourceUtf8(RemoveAllDomainContactsAction.class, "domain_remove_contacts.xml");
@@ -146,7 +151,10 @@ private void runLocked() {
146151
.setMaxResults(BATCH_SIZE)
147152
.getResultList());
148153

149-
domainRepoIdsBatch.forEach(this::runDomainUpdateFlow);
154+
for (String domainRepoId : domainRepoIdsBatch) {
155+
rateLimiter.acquire();
156+
runDomainUpdateFlow(domainRepoId);
157+
}
150158
} while (!domainRepoIdsBatch.isEmpty());
151159
String msg =
152160
String.format(

core/src/test/java/google/registry/batch/RemoveAllDomainContactsActionTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import static google.registry.testing.DatabaseHelper.persistActiveContact;
2424
import static google.registry.testing.DatabaseHelper.persistResource;
2525
import static google.registry.util.DateTimeUtils.START_OF_TIME;
26+
import static org.mockito.Mockito.mock;
2627

2728
import com.google.common.collect.ImmutableSet;
2829
import com.google.common.collect.ImmutableSortedMap;
30+
import com.google.common.util.concurrent.RateLimiter;
2931
import google.registry.flows.DaggerEppTestComponent;
3032
import google.registry.flows.EppController;
3133
import google.registry.flows.EppTestComponent.FakesAndMocksModule;
@@ -51,6 +53,7 @@ class RemoveAllDomainContactsActionTest {
5153
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
5254

5355
private final FakeResponse response = new FakeResponse();
56+
private final RateLimiter rateLimiter = mock(RateLimiter.class);
5457
private RemoveAllDomainContactsAction action;
5558

5659
@BeforeEach
@@ -69,7 +72,7 @@ void beforeEach() {
6972
.eppController();
7073
action =
7174
new RemoveAllDomainContactsAction(
72-
eppController, "NewRegistrar", new FakeLockHandler(true), response);
75+
eppController, "NewRegistrar", new FakeLockHandler(true), rateLimiter, response);
7376
}
7477

7578
@Test

0 commit comments

Comments
 (0)