From 58c24a53177df6bd02e56a5755de69a3d4b30539 Mon Sep 17 00:00:00 2001 From: Jon Marius Venstad Date: Tue, 6 Jul 2021 09:55:06 +0200 Subject: Uses last non-redeployment start in /application/v4, and fix tests --- .../hosted/controller/deployment/JobController.java | 9 +++++++++ .../hosted/controller/maintenance/DeploymentExpirer.java | 8 +++----- .../controller/maintenance/DeploymentUpgrader.java | 13 ++++++------- .../restapi/application/ApplicationApiHandler.java | 16 +++++++++++----- .../controller/maintenance/DeploymentUpgraderTest.java | 6 +++--- .../restapi/controller/responses/maintenance.json | 3 +++ 6 files changed, 35 insertions(+), 20 deletions(-) (limited to 'controller-server') diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java index 2281d98bb3d..28a6d32ce54 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java @@ -48,6 +48,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.UnaryOperator; import java.util.logging.Level; +import java.util.stream.Collectors; import java.util.stream.Stream; import static com.google.common.collect.ImmutableList.copyOf; @@ -230,6 +231,14 @@ public class JobController { return runs(id.application(), id.type()); } + /** Lists the start time of non-redeployment runs of the given job, in order of increasing age. */ + public List jobStarts(JobId id) { + return runs(id).descendingMap().values().stream() + .filter(run -> ! run.isRedeployment()) + .map(Run::start) + .collect(toUnmodifiableList()); + } + /** Returns an immutable map of all known runs for the given application and job type. */ public NavigableMap runs(ApplicationId id, JobType type) { ImmutableSortedMap.Builder runs = ImmutableSortedMap.orderedBy(Comparator.comparing(RunId::number)); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirer.java index 76fb63393e6..40191190eff 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentExpirer.java @@ -12,6 +12,7 @@ import com.yahoo.vespa.hosted.controller.deployment.Run; import com.yahoo.yolean.Exceptions; import java.time.Duration; +import java.time.Instant; import java.util.Optional; import java.util.logging.Level; @@ -62,11 +63,8 @@ public class DeploymentExpirer extends ControllerMaintainer { .map(type -> new JobId(instance, type)); if (jobId.isEmpty()) return false; - return controller().jobController().jobStatus(jobId.get()) - .runs().descendingMap().values().stream() - .filter(run -> ! run.isRedeployment()) - .findFirst() - .map(run -> run.start().plus(ttl.get()).isBefore(controller().clock().instant())) + return controller().jobController().jobStarts(jobId.get()).stream().findFirst() + .map(start -> start.plus(ttl.get()).isBefore(controller().clock().instant())) .orElse(false); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java index d40ad8e9f6c..a69af024b96 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgrader.java @@ -57,33 +57,32 @@ public class DeploymentUpgrader extends ControllerMaintainer { private boolean isLikelyNightFor(JobId job) { int hour = hourOf(controller().clock().instant()); - int[] runStarts = controller().jobController().runs(job).descendingMap().values().stream() - .filter(run -> ! run.isRedeployment()) - .mapToInt(run -> hourOf(run.start())) + int[] runStarts = controller().jobController().jobStarts(job).stream() + .mapToInt(DeploymentUpgrader::hourOf) .toArray(); int localNight = mostLikelyWeeHour(runStarts); return Math.abs(hour - localNight) <= 1; } static int mostLikelyWeeHour(int[] starts) { - double weight = 1; // Weight more recent deployments higher. + double weight = 1; double[] buckets = new double[24]; for (int start : starts) - buckets[start] += weight *= (Math.sqrt(5) - 1) * 0.5; // When in doubt, use the golden ratio. + buckets[start] += weight *= 0.8; // Weight more recent deployments higher. int best = -1; double min = Double.MAX_VALUE; for (int i = 12; i < 36; i++) { double sum = 0; for (int j = -12; j < 12; j++) - sum += Math.abs(j) * buckets[(i + j) % 24]; + sum += buckets[(i + j) % 24] / (Math.abs(j) + 1); if (sum < min) { min = sum; best = i; } } - return (best + 13) % 24; // rot13 of weighted average deployment start is likely in the middle of the night. + return (best + 2) % 24; } private static int hourOf(Instant instant) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index d022588c757..5026f0552b3 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -1383,9 +1383,10 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { response.setString("yamasUrl", monitoringSystemUri(deploymentId).toString()); response.setString("version", deployment.version().toFullString()); response.setString("revision", deployment.applicationVersion().id()); - response.setLong("deployTimeEpochMs", deployment.at().toEpochMilli()); + Instant lastDeploymentStart = lastDeploymentStart(deploymentId.applicationId(), deployment); + response.setLong("deployTimeEpochMs", lastDeploymentStart.toEpochMilli()); controller.zoneRegistry().getDeploymentTimeToLive(deploymentId.zoneId()) - .ifPresent(deploymentTimeToLive -> response.setLong("expiryTimeEpochMs", deployment.at().plus(deploymentTimeToLive).toEpochMilli())); + .ifPresent(deploymentTimeToLive -> response.setLong("expiryTimeEpochMs", lastDeploymentStart.plus(deploymentTimeToLive).toEpochMilli())); DeploymentStatus status = controller.jobController().deploymentStatus(application); application.projectId().ifPresent(i -> response.setString("screwdriverId", String.valueOf(i))); @@ -1435,6 +1436,11 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { metrics.instant().ifPresent(instant -> metricsObject.setLong("lastUpdated", instant.toEpochMilli())); } + private Instant lastDeploymentStart(ApplicationId instanceId, Deployment deployment) { + return controller.jobController().jobStarts(new JobId(instanceId, JobType.from(controller.system(), deployment.zone()).get())) + .stream().findFirst().orElse(deployment.at()); + } + private void toSlime(ApplicationVersion applicationVersion, Cursor object) { if ( ! applicationVersion.isUnknown()) { object.setLong("buildNumber", applicationVersion.buildNumber().getAsLong()); @@ -2187,9 +2193,9 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { private void tenantMetaDataToSlime(Tenant tenant, List applications, Cursor object) { Optional lastDev = applications.stream() .flatMap(application -> application.instances().values().stream()) - .flatMap(instance -> instance.deployments().values().stream()) - .filter(deployment -> deployment.zone().environment() == Environment.dev) - .map(Deployment::at) + .flatMap(instance -> instance.deployments().values().stream() + .filter(deployment -> deployment.zone().environment() == Environment.dev) + .map(deployment -> lastDeploymentStart(instance.id(), deployment))) .max(Comparator.naturalOrder()) .or(() -> applications.stream() .flatMap(application -> application.instances().values().stream()) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java index b4a78e55f62..552a38e6678 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/DeploymentUpgraderTest.java @@ -92,10 +92,10 @@ public class DeploymentUpgraderTest { @Test public void testNight() { - assertEquals(14, mostLikelyWeeHour(new int[]{ 0, 1, 2, 3, 4, 5, 6 })); - assertEquals(12, mostLikelyWeeHour(new int[]{ 22, 23, 0, 1, 2, 3, 4 })); + assertEquals(16, mostLikelyWeeHour(new int[]{ 0, 1, 2, 3, 4, 5, 6 })); + assertEquals(14, mostLikelyWeeHour(new int[]{ 22, 23, 0, 1, 2, 3, 4 })); assertEquals(18, mostLikelyWeeHour(new int[]{ 6, 5, 4, 3, 2, 1, 0 })); - assertEquals(13, mostLikelyWeeHour(new int[]{ 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12 })); + assertEquals(20, mostLikelyWeeHour(new int[]{ 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 11 })); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json index e906df94023..668baa50cc1 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/controller/responses/maintenance.json @@ -42,6 +42,9 @@ { "name": "DeploymentMetricsMaintainer" }, + { + "name": "DeploymentUpgrader" + }, { "name": "EndpointCertificateMaintainer" }, -- cgit v1.2.3