Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import com.google.monitoring.metrics.IncrementableMetric;
import com.google.monitoring.metrics.LabelDescriptor;
import com.google.monitoring.metrics.MetricRegistryImpl;
import google.registry.cache.SimplifiedJedisClient;
import google.registry.model.EppResource;
import google.registry.model.common.Cursor;
Expand All @@ -39,6 +42,7 @@
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.lock.LockHandler;
import google.registry.util.NonFinalForTesting;
import jakarta.inject.Inject;
import java.time.Duration;
import java.time.Instant;
Expand All @@ -61,6 +65,25 @@ public class SyncRemoteCacheAction implements Runnable {
private static final String LOCK_NAME = "syncRemoteCacheAction";
private static final int BATCH_SIZE = 10000;

public enum SyncStatus {
SUCCESS,
FAILURE,
NOT_CONFIGURED
}

private static final ImmutableSet<LabelDescriptor> LABEL_DESCRIPTORS =
ImmutableSet.of(
LabelDescriptor.create("status", "Whether SyncRemoteCacheAction succeeded or failed."));

@NonFinalForTesting
static final IncrementableMetric SYNC_CACHE_RUNS_METRIC =
MetricRegistryImpl.getDefault()
.newIncrementableMetric(
"/batch/sync_remote_cache/runs",
"Count of SyncRemoteCacheAction executions",
"count",
LABEL_DESCRIPTORS);

private final LockHandler lockHandler;
private final Response response;
private final Optional<SimplifiedJedisClient> jedisClient;
Expand All @@ -79,14 +102,17 @@ public void run() {
if (jedisClient.isEmpty()) {
response.setStatus(SC_NO_CONTENT);
response.setPayload("No Jedis/Valkey configuration found");
SYNC_CACHE_RUNS_METRIC.increment(SyncStatus.NOT_CONFIGURED.name());
return;
}
Callable<Void> runner =
() -> {
try {
runLocked();
SYNC_CACHE_RUNS_METRIC.increment(SyncStatus.SUCCESS.name());
response.setStatus(SC_OK);
} catch (Exception e) {
SYNC_CACHE_RUNS_METRIC.increment(SyncStatus.FAILURE.name());
logger.atSevere().withCause(e).log("Errored out during execution.");
response.setStatus(SC_INTERNAL_SERVER_ERROR);
response.setPayload(String.format("Errored out with cause: %s", e));
Expand All @@ -95,6 +121,7 @@ public void run() {
};

if (!lockHandler.executeWithLocks(runner, null, Duration.ofHours(1), LOCK_NAME)) {
SYNC_CACHE_RUNS_METRIC.increment(SyncStatus.FAILURE.name());
// Send a 200-series status code to prevent this conflicting action from retrying.
response.setStatus(SC_NO_CONTENT);
response.setPayload("Could not acquire lock; already running?");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
package google.registry.batch;

import static com.google.common.truth.Truth.assertThat;
import static com.google.monitoring.metrics.contrib.LongMetricSubject.assertThat;
import static google.registry.batch.SyncRemoteCacheAction.SyncStatus.FAILURE;
import static google.registry.batch.SyncRemoteCacheAction.SyncStatus.NOT_CONFIGURED;
import static google.registry.batch.SyncRemoteCacheAction.SyncStatus.SUCCESS;
import static google.registry.model.common.Cursor.CursorType.REMOTE_CACHE_DOMAIN_SYNC;
import static google.registry.model.common.Cursor.CursorType.REMOTE_CACHE_HOST_SYNC;
import static google.registry.testing.DatabaseHelper.createTld;
Expand Down Expand Up @@ -73,15 +77,24 @@ class SyncRemoteCacheActionTest {
@BeforeEach
void beforeEach() {
createTld("tld");
SyncRemoteCacheAction.SYNC_CACHE_RUNS_METRIC.reset();
action = new SyncRemoteCacheAction(lockHandler, response, Optional.of(jedisClient));
}

private static void verifyMetrics(SyncRemoteCacheAction.SyncStatus status) {
assertThat(SyncRemoteCacheAction.SYNC_CACHE_RUNS_METRIC)
.hasValueForLabels(1, status.name())
.and()
.hasNoOtherValues();
}

@Test
void test_noJedisConfig() {
action = new SyncRemoteCacheAction(lockHandler, response, Optional.empty());
action.run();
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
assertThat(response.getPayload()).contains("No Jedis/Valkey configuration found");
verifyMetrics(NOT_CONFIGURED);
}

@Test
Expand All @@ -91,6 +104,7 @@ void test_lockAcquisitionFails() {
action.run();
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
assertThat(response.getPayload()).contains("Could not acquire lock");
verifyMetrics(FAILURE);
}

@Test
Expand All @@ -100,6 +114,7 @@ void test_exceptionThrown() {
action.run();
assertThat(response.getStatus()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
assertThat(response.getPayload()).contains("Errored out with cause");
verifyMetrics(FAILURE);
}

@Test
Expand All @@ -109,6 +124,7 @@ void test_syncDomains_noDomains() {
verifyNoInteractions(jedisClient);
assertThat(DatabaseHelper.loadByKeyIfPresent(Cursor.createGlobalVKey(REMOTE_CACHE_DOMAIN_SYNC)))
.isEmpty();
verifyMetrics(SUCCESS);
}

@Test
Expand All @@ -131,6 +147,7 @@ void test_syncDomains_withDomains() {
.getCursorTime()
.toString())
.isEqualTo("2025-01-01T00:00:00.001Z");
verifyMetrics(SUCCESS);
}

@Test
Expand All @@ -146,6 +163,7 @@ void test_syncDomains_withDeletedDomains() {
ImmutableList.of(
new SimplifiedJedisClient.JedisResource<>("active.tld", activeDomain)));
verify(jedisClient).deleteAll(Domain.class, ImmutableList.of("deleted.tld"));
verifyMetrics(SUCCESS);
}

@Test
Expand All @@ -166,6 +184,7 @@ void testCursorTime_skipsOldChange() {
verify(jedisClient)
.setAll(
ImmutableList.of(new SimplifiedJedisClient.JedisResource<>("example2.tld", domain2)));
verifyMetrics(SUCCESS);
}

@Test
Expand All @@ -175,6 +194,7 @@ void test_syncHosts_noHosts() {
verifyNoInteractions(jedisClient);
assertThat(DatabaseHelper.loadByKeyIfPresent(Cursor.createGlobalVKey(REMOTE_CACHE_HOST_SYNC)))
.isEmpty();
verifyMetrics(SUCCESS);
}

@Test
Expand All @@ -197,6 +217,7 @@ void test_syncHosts_withHosts() {
.getCursorTime()
.toString())
.isEqualTo("2025-01-01T00:00:00.001Z");
verifyMetrics(SUCCESS);
}

@Test
Expand All @@ -212,5 +233,6 @@ void test_syncHosts_withDeletedHosts() {
ImmutableList.of(
new SimplifiedJedisClient.JedisResource<>(active.getRepoId(), active)));
verify(jedisClient).deleteAll(Host.class, ImmutableList.of(deleted.getRepoId()));
verifyMetrics(SUCCESS);
}
}
Loading