diff --git a/java/google/registry/env/common/backend/WEB-INF/web.xml b/java/google/registry/env/common/backend/WEB-INF/web.xml
index 8e02c28f2..234ee241b 100644
--- a/java/google/registry/env/common/backend/WEB-INF/web.xml
+++ b/java/google/registry/env/common/backend/WEB-INF/web.xml
@@ -141,6 +141,12 @@
/_dr/task/loadSnapshot
+
+
+ backend-servlet
+ /_dr/task/refreshAllDomains
+
+
backend-servlet
diff --git a/java/google/registry/module/backend/BUILD b/java/google/registry/module/backend/BUILD
index e5b470a89..db64fc4b9 100644
--- a/java/google/registry/module/backend/BUILD
+++ b/java/google/registry/module/backend/BUILD
@@ -25,7 +25,6 @@ java_library(
"//java/google/registry/config",
"//java/google/registry/cron",
"//java/google/registry/dns",
- "//java/google/registry/dns/writer",
"//java/google/registry/dns/writer/clouddns",
"//java/google/registry/dns/writer/dnsupdate",
"//java/google/registry/export",
@@ -42,6 +41,7 @@ java_library(
"//java/google/registry/request:modules",
"//java/google/registry/tmch",
"//java/google/registry/util",
+ "//java/google/registry/tools/server/javascrap",
],
)
diff --git a/java/google/registry/module/backend/BackendRequestComponent.java b/java/google/registry/module/backend/BackendRequestComponent.java
index a3ff37a1a..1016bb571 100644
--- a/java/google/registry/module/backend/BackendRequestComponent.java
+++ b/java/google/registry/module/backend/BackendRequestComponent.java
@@ -62,6 +62,7 @@ import google.registry.tmch.TmchCrlAction;
import google.registry.tmch.TmchDnlAction;
import google.registry.tmch.TmchModule;
import google.registry.tmch.TmchSmdrlAction;
+import google.registry.tools.server.javascrap.RefreshAllDomainsAction;
/** Dagger component with per-request lifetime for "backend" App Engine module. */
@RequestScope
@@ -106,6 +107,7 @@ interface BackendRequestComponent {
RdeStagingAction rdeStagingAction();
RdeUploadAction rdeUploadAction();
RdeReporter rdeReporter();
+ RefreshAllDomainsAction refreshAllDomainsAction();
RefreshDnsAction refreshDnsAction();
RestoreCommitLogsAction restoreCommitLogsAction();
SyncGroupMembersAction syncGroupMembersAction();
diff --git a/java/google/registry/tools/server/javascrap/BUILD b/java/google/registry/tools/server/javascrap/BUILD
index 96180035e..43f9bcfb6 100644
--- a/java/google/registry/tools/server/javascrap/BUILD
+++ b/java/google/registry/tools/server/javascrap/BUILD
@@ -14,9 +14,11 @@ java_library(
"//third_party/java/appengine:appengine-api",
"//third_party/java/appengine_mapreduce2:appengine_mapreduce",
"//third_party/java/dagger",
+ "//third_party/java/joda_time",
"//third_party/java/jsr305_annotations",
"//third_party/java/jsr330_inject",
"//third_party/java/objectify:objectify-v4_1",
+ "//java/google/registry/dns",
"//java/google/registry/mapreduce",
"//java/google/registry/mapreduce/inputs",
"//java/google/registry/model",
diff --git a/java/google/registry/tools/server/javascrap/RefreshAllDomainsAction.java b/java/google/registry/tools/server/javascrap/RefreshAllDomainsAction.java
new file mode 100644
index 000000000..271bfbf95
--- /dev/null
+++ b/java/google/registry/tools/server/javascrap/RefreshAllDomainsAction.java
@@ -0,0 +1,79 @@
+// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package google.registry.tools.server.javascrap;
+
+import static google.registry.mapreduce.inputs.EppResourceInputs.createEntityInput;
+import static google.registry.util.PipelineUtils.createJobPath;
+
+import com.google.appengine.tools.mapreduce.Mapper;
+import com.google.common.collect.ImmutableList;
+import google.registry.dns.DnsQueue;
+import google.registry.mapreduce.MapreduceRunner;
+import google.registry.model.EppResourceUtils;
+import google.registry.model.domain.DomainResource;
+import google.registry.request.Action;
+import google.registry.request.Response;
+import google.registry.util.FormattingLogger;
+import javax.inject.Inject;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+/** A mapreduce that runs publishHost() on all active domains. */
+@Action(path = "/_dr/task/refreshAllDomains")
+public class RefreshAllDomainsAction implements Runnable {
+
+ private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
+
+ static DnsQueue dnsQueue = DnsQueue.create();
+
+ @Inject MapreduceRunner mrRunner;
+ @Inject Response response;
+ @Inject RefreshAllDomainsAction() {}
+
+ @Override
+ public void run() {
+ response.sendJavaScriptRedirect(
+ createJobPath(
+ mrRunner
+ .setJobName("Refresh all domains")
+ .setModuleName("backend")
+ .setDefaultMapShards(10)
+ .runMapOnly(
+ new RefreshAllDomainsActionMapper(),
+ ImmutableList.of(createEntityInput(DomainResource.class)))));
+ }
+
+ /** Mapper to refresh all active domain resources. */
+ public static class RefreshAllDomainsActionMapper extends Mapper {
+
+ private static final long serialVersionUID = 1356876487351666133L;
+
+ @Override
+ public final void map(final DomainResource domain) {
+ final String domainName = domain.getFullyQualifiedDomainName();
+ if (EppResourceUtils.isActive(domain, DateTime.now(DateTimeZone.UTC))) {
+ try {
+ dnsQueue.addDomainRefreshTask(domainName);
+ getContext().incrementCounter("active domains refreshed");
+ } catch (Throwable t) {
+ logger.severefmt(t, "Error while refreshing DNS for domain %s", domainName);
+ getContext().incrementCounter("active domains errored");
+ }
+ } else {
+ getContext().incrementCounter("inactive domains skipped");
+ }
+ }
+ }
+}