mirror of
https://github.com/google/nomulus.git
synced 2025-05-27 22:50:08 +02:00
Refactor LordnTask to LordnTaskUtils
Made it clear that it is a util class and moved some of the functions only used in NordnUploadAction (to NordnUploadAction). Also used Retrier to handle retries when leasing tasks. These changes allow us to no longer use InjectRule in related unit tests. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=217761117
This commit is contained in:
parent
0f1f418034
commit
b254269d2f
10 changed files with 170 additions and 176 deletions
|
@ -88,7 +88,7 @@ import google.registry.model.reporting.DomainTransactionRecord;
|
|||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.tmch.LordnTask;
|
||||
import google.registry.tmch.LordnTaskUtils;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.inject.Inject;
|
||||
|
@ -385,7 +385,7 @@ public class DomainAllocateFlow implements TransactionalFlow {
|
|||
dnsQueue.get().addDomainRefreshTask(newDomain.getFullyQualifiedDomainName());
|
||||
}
|
||||
if (allocateCreate.getSmdId() != null || allocateCreate.getNotice() != null) {
|
||||
LordnTask.enqueueDomainResourceTask(newDomain);
|
||||
LordnTaskUtils.enqueueDomainResourceTask(newDomain);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ import google.registry.model.reporting.DomainTransactionRecord;
|
|||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.tmch.LordnTask;
|
||||
import google.registry.tmch.LordnTaskUtils;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
|
@ -608,7 +608,7 @@ public class DomainCreateFlow implements TransactionalFlow {
|
|||
dnsQueue.addDomainRefreshTask(newDomain.getFullyQualifiedDomainName());
|
||||
}
|
||||
if (hasClaimsNotice || hasSignedMarks) {
|
||||
LordnTask.enqueueDomainResourceTask(newDomain);
|
||||
LordnTaskUtils.enqueueDomainResourceTask(newDomain);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,36 +15,22 @@
|
|||
package google.registry.tmch;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
|
||||
import com.google.appengine.api.taskqueue.LeaseOptions;
|
||||
import com.google.appengine.api.taskqueue.Queue;
|
||||
import com.google.appengine.api.taskqueue.TaskHandle;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||
import com.google.appengine.api.taskqueue.TransientFailureException;
|
||||
import com.google.apphosting.api.DeadlineExceededException;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import google.registry.util.TaskQueueUtils;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Helper methods for creating tasks containing CSV line data in the lordn-sunrise and lordn-claims
|
||||
* queues based on DomainResource changes.
|
||||
*/
|
||||
public class LordnTask {
|
||||
public final class LordnTaskUtils {
|
||||
|
||||
public static final String QUEUE_SUNRISE = "lordn-sunrise";
|
||||
public static final String QUEUE_CLAIMS = "lordn-claims";
|
||||
|
@ -52,51 +38,6 @@ public class LordnTask {
|
|||
+ "registration-datetime,ack-datetime,application-datetime";
|
||||
public static final String COLUMNS_SUNRISE = "roid,domain-name,SMD-id,registrar-id,"
|
||||
+ "registration-datetime,application-datetime";
|
||||
private static final Duration LEASE_PERIOD = Duration.standardHours(1);
|
||||
|
||||
@NonFinalForTesting
|
||||
private static Long backOffMillis = 2000L;
|
||||
|
||||
/**
|
||||
* Converts a list of queue tasks, each containing a row of CSV data, into a single newline-
|
||||
* delimited String.
|
||||
*/
|
||||
public static String convertTasksToCsv(List<TaskHandle> tasks, DateTime now, String columns) {
|
||||
String header = String.format("1,%s,%d\n%s\n", now, tasks.size(), columns);
|
||||
StringBuilder csv = new StringBuilder(header);
|
||||
for (TaskHandle task : checkNotNull(tasks)) {
|
||||
String payload = new String(task.getPayload());
|
||||
if (!Strings.isNullOrEmpty(payload)) {
|
||||
csv.append(payload).append("\n");
|
||||
}
|
||||
}
|
||||
return csv.toString();
|
||||
}
|
||||
|
||||
/** Leases and returns all tasks from the queue with the specified tag tld, in batches. */
|
||||
public static List<TaskHandle> loadAllTasks(Queue queue, String tld) {
|
||||
ImmutableList.Builder<TaskHandle> allTasks = new ImmutableList.Builder<>();
|
||||
int numErrors = 0;
|
||||
long backOff = backOffMillis;
|
||||
while (true) {
|
||||
try {
|
||||
List<TaskHandle> tasks = queue.leaseTasks(LeaseOptions.Builder
|
||||
.withTag(tld)
|
||||
.leasePeriod(LEASE_PERIOD.getMillis(), TimeUnit.MILLISECONDS)
|
||||
.countLimit(TaskQueueUtils.getBatchSize()));
|
||||
allTasks.addAll(tasks);
|
||||
if (tasks.isEmpty()) {
|
||||
return allTasks.build();
|
||||
}
|
||||
} catch (TransientFailureException | DeadlineExceededException e) {
|
||||
if (++numErrors >= 3) {
|
||||
throw new RuntimeException("Error leasing tasks", e);
|
||||
}
|
||||
Uninterruptibles.sleepUninterruptibly(backOff, TimeUnit.MILLISECONDS);
|
||||
backOff *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a task in the LORDN queue representing a line of CSV for LORDN export.
|
||||
|
@ -156,4 +97,6 @@ public class LordnTask {
|
|||
// have null iana ids.
|
||||
return String.valueOf(registrar.get().getIanaIdentifier());
|
||||
}
|
||||
|
||||
private LordnTaskUtils() {}
|
||||
}
|
|
@ -19,21 +19,27 @@ import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
|
|||
import static com.google.appengine.api.urlfetch.FetchOptions.Builder.validateCertificate;
|
||||
import static com.google.appengine.api.urlfetch.HTTPMethod.POST;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||
import static com.google.common.net.MediaType.CSV_UTF_8;
|
||||
import static google.registry.tmch.LordnTask.COLUMNS_CLAIMS;
|
||||
import static google.registry.tmch.LordnTask.COLUMNS_SUNRISE;
|
||||
import static google.registry.tmch.LordnTask.convertTasksToCsv;
|
||||
import static google.registry.tmch.LordnTaskUtils.COLUMNS_CLAIMS;
|
||||
import static google.registry.tmch.LordnTaskUtils.COLUMNS_SUNRISE;
|
||||
import static google.registry.util.UrlFetchUtils.getHeaderFirst;
|
||||
import static google.registry.util.UrlFetchUtils.setPayloadMultipart;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
||||
|
||||
import com.google.appengine.api.taskqueue.LeaseOptions;
|
||||
import com.google.appengine.api.taskqueue.Queue;
|
||||
import com.google.appengine.api.taskqueue.TaskHandle;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||
import com.google.appengine.api.taskqueue.TransientFailureException;
|
||||
import com.google.appengine.api.urlfetch.HTTPRequest;
|
||||
import com.google.appengine.api.urlfetch.HTTPResponse;
|
||||
import com.google.appengine.api.urlfetch.URLFetchService;
|
||||
import com.google.apphosting.api.DeadlineExceededException;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.Action;
|
||||
|
@ -41,6 +47,7 @@ import google.registry.request.Parameter;
|
|||
import google.registry.request.RequestParameters;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.util.Retrier;
|
||||
import google.registry.util.TaskQueueUtils;
|
||||
import google.registry.util.UrlFetchException;
|
||||
import java.io.IOException;
|
||||
|
@ -48,29 +55,30 @@ import java.net.URL;
|
|||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Action that reads the NORDN pull queues, uploads claims and sunrise marks data to TMCH, and
|
||||
* enqueues subsequent upload verification tasks. A unique actionLogId is generated and passed
|
||||
* along to the verify action so that connected verify tasks can be identified by looking at logs.
|
||||
* enqueues subsequent upload verification tasks. A unique actionLogId is generated and passed along
|
||||
* to the verify action so that connected verify tasks can be identified by looking at logs.
|
||||
*
|
||||
* @see NordnVerifyAction
|
||||
*/
|
||||
@Action(
|
||||
path = NordnUploadAction.PATH,
|
||||
method = Action.Method.POST,
|
||||
automaticallyPrintOk = true,
|
||||
auth = Auth.AUTH_INTERNAL_ONLY
|
||||
)
|
||||
path = NordnUploadAction.PATH,
|
||||
method = Action.Method.POST,
|
||||
automaticallyPrintOk = true,
|
||||
auth = Auth.AUTH_INTERNAL_ONLY)
|
||||
public final class NordnUploadAction implements Runnable {
|
||||
|
||||
static final String PATH = "/_dr/task/nordnUpload";
|
||||
static final String LORDN_PHASE_PARAM = "lordn-phase";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
private static final Duration LEASE_PERIOD = Duration.standardHours(1);
|
||||
|
||||
/**
|
||||
* A unique (enough) id that is outputted in log lines to make it clear which log lines are
|
||||
|
@ -80,6 +88,7 @@ public final class NordnUploadAction implements Runnable {
|
|||
private final String actionLogId = String.valueOf(1000000000 + new Random().nextInt(1000000000));
|
||||
|
||||
@Inject Clock clock;
|
||||
@Inject Retrier retrier;
|
||||
@Inject Random random;
|
||||
@Inject LordnRequestInitializer lordnRequestInitializer;
|
||||
@Inject URLFetchService fetchService;
|
||||
|
@ -108,15 +117,54 @@ public final class NordnUploadAction implements Runnable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a list of queue tasks, each containing a row of CSV data, into a single newline-
|
||||
* delimited String.
|
||||
*/
|
||||
static String convertTasksToCsv(List<TaskHandle> tasks, DateTime now, String columns) {
|
||||
String header = String.format("1,%s,%d\n%s\n", now, tasks.size(), columns);
|
||||
StringBuilder csv = new StringBuilder(header);
|
||||
for (TaskHandle task : checkNotNull(tasks)) {
|
||||
String payload = new String(task.getPayload(), UTF_8);
|
||||
if (!Strings.isNullOrEmpty(payload)) {
|
||||
csv.append(payload).append("\n");
|
||||
}
|
||||
}
|
||||
return csv.toString();
|
||||
}
|
||||
|
||||
/** Leases and returns all tasks from the queue with the specified tag tld, in batches. */
|
||||
List<TaskHandle> loadAllTasks(Queue queue, String tld) {
|
||||
ImmutableList.Builder<TaskHandle> allTasks = new ImmutableList.Builder<>();
|
||||
while (true) {
|
||||
List<TaskHandle> tasks =
|
||||
retrier.callWithRetry(
|
||||
() ->
|
||||
queue.leaseTasks(
|
||||
LeaseOptions.Builder.withTag(tld)
|
||||
.leasePeriod(LEASE_PERIOD.getMillis(), TimeUnit.MILLISECONDS)
|
||||
.countLimit(TaskQueueUtils.getBatchSize())),
|
||||
TransientFailureException.class,
|
||||
DeadlineExceededException.class);
|
||||
if (tasks.isEmpty()) {
|
||||
return allTasks.build();
|
||||
}
|
||||
allTasks.addAll(tasks);
|
||||
}
|
||||
}
|
||||
|
||||
private void processLordnTasks() throws IOException {
|
||||
checkArgument(phase.equals(PARAM_LORDN_PHASE_SUNRISE)
|
||||
|| phase.equals(PARAM_LORDN_PHASE_CLAIMS),
|
||||
"Invalid phase specified to Nordn servlet: %s.", phase);
|
||||
DateTime now = clock.nowUtc();
|
||||
Queue queue = getQueue(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? LordnTask.QUEUE_SUNRISE : LordnTask.QUEUE_CLAIMS);
|
||||
Queue queue =
|
||||
getQueue(
|
||||
phase.equals(PARAM_LORDN_PHASE_SUNRISE)
|
||||
? LordnTaskUtils.QUEUE_SUNRISE
|
||||
: LordnTaskUtils.QUEUE_CLAIMS);
|
||||
String columns = phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? COLUMNS_SUNRISE : COLUMNS_CLAIMS;
|
||||
List<TaskHandle> tasks = LordnTask.loadAllTasks(queue, tld);
|
||||
List<TaskHandle> tasks = loadAllTasks(queue, tld);
|
||||
if (!tasks.isEmpty()) {
|
||||
String csvData = convertTasksToCsv(tasks, now, columns);
|
||||
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), csvData);
|
||||
|
@ -146,16 +194,19 @@ public final class NordnUploadAction implements Runnable {
|
|||
actionLogId, rsp.getResponseCode(), rsp.getContent());
|
||||
if (rsp.getResponseCode() != SC_ACCEPTED) {
|
||||
throw new UrlFetchException(
|
||||
String.format("LORDN upload task %s error: Failed to upload LORDN claims to MarksDB",
|
||||
actionLogId),
|
||||
req, rsp);
|
||||
String.format(
|
||||
"LORDN upload task %s error: Failed to upload LORDN claims to MarksDB", actionLogId),
|
||||
req,
|
||||
rsp);
|
||||
}
|
||||
Optional<String> location = getHeaderFirst(rsp, LOCATION);
|
||||
if (!location.isPresent()) {
|
||||
throw new UrlFetchException(
|
||||
String.format("LORDN upload task %s error: MarksDB failed to provide a Location header",
|
||||
String.format(
|
||||
"LORDN upload task %s error: MarksDB failed to provide a Location header",
|
||||
actionLogId),
|
||||
req, rsp);
|
||||
req,
|
||||
rsp);
|
||||
}
|
||||
getQueue(NordnVerifyAction.QUEUE).add(makeVerifyTask(new URL(location.get())));
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import com.beust.jcommander.Parameter;
|
|||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.DomainResource;
|
||||
import google.registry.tmch.LordnTask;
|
||||
import google.registry.tmch.LordnTaskUtils;
|
||||
import google.registry.tools.params.PathParameter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
@ -61,26 +61,28 @@ final class GenerateLordnCommand implements CommandWithRemoteApi {
|
|||
for (DomainResource domain : ofy().load().type(DomainResource.class).filter("tld", tld)) {
|
||||
String status = " ";
|
||||
if (domain.getLaunchNotice() == null && domain.getSmdId() != null) {
|
||||
sunriseCsv.add(LordnTask.getCsvLineForSunriseDomain(domain, domain.getCreationTime()));
|
||||
sunriseCsv.add(LordnTaskUtils.getCsvLineForSunriseDomain(domain, domain.getCreationTime()));
|
||||
status = "S";
|
||||
} else if (domain.getLaunchNotice() != null || domain.getSmdId() != null) {
|
||||
claimsCsv.add(LordnTask.getCsvLineForClaimsDomain(domain, domain.getCreationTime()));
|
||||
claimsCsv.add(LordnTaskUtils.getCsvLineForClaimsDomain(domain, domain.getCreationTime()));
|
||||
status = "C";
|
||||
}
|
||||
System.out.printf("%s[%s] ", domain.getFullyQualifiedDomainName(), status);
|
||||
}
|
||||
ImmutableList<String> claimsRows = claimsCsv.build();
|
||||
ImmutableList<String> claimsAll = new ImmutableList.Builder<String>()
|
||||
.add(String.format("1,%s,%d", now, claimsRows.size()))
|
||||
.add(LordnTask.COLUMNS_CLAIMS)
|
||||
.addAll(claimsRows)
|
||||
.build();
|
||||
ImmutableList<String> claimsAll =
|
||||
new ImmutableList.Builder<String>()
|
||||
.add(String.format("1,%s,%d", now, claimsRows.size()))
|
||||
.add(LordnTaskUtils.COLUMNS_CLAIMS)
|
||||
.addAll(claimsRows)
|
||||
.build();
|
||||
ImmutableList<String> sunriseRows = sunriseCsv.build();
|
||||
ImmutableList<String> sunriseAll = new ImmutableList.Builder<String>()
|
||||
.add(String.format("1,%s,%d", now.plusMillis(1), sunriseRows.size()))
|
||||
.add(LordnTask.COLUMNS_SUNRISE)
|
||||
.addAll(sunriseRows)
|
||||
.build();
|
||||
ImmutableList<String> sunriseAll =
|
||||
new ImmutableList.Builder<String>()
|
||||
.add(String.format("1,%s,%d", now.plusMillis(1), sunriseRows.size()))
|
||||
.add(LordnTaskUtils.COLUMNS_SUNRISE)
|
||||
.addAll(sunriseRows)
|
||||
.build();
|
||||
Files.write(claimsOutputPath, claimsAll, UTF_8);
|
||||
Files.write(sunriseOutputPath, sunriseAll, UTF_8);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue