private boolean autoscale(ApplicationId applicationId, ClusterSpec.Id clusterId) {
        boolean redeploy = false;
        boolean enabled = enabledFlag.with(Dimension.INSTANCE_ID, applicationId.serializedForm()).value();
        boolean logDetails = enableDetailedLoggingFlag.with(Dimension.INSTANCE_ID, applicationId.serializedForm()).value();
        try (var lock = nodeRepository().applications().lock(applicationId)) {
            Optional<Application> application = nodeRepository().applications().get(applicationId);
            if (application.isEmpty()) return true;
            if (application.get().cluster(clusterId).isEmpty()) return true;
            Cluster cluster = application.get().cluster(clusterId).get();
            Cluster unchangedCluster = cluster;

            NodeList clusterNodes = nodeRepository().nodes().list(Node.State.active).owner(applicationId).cluster(clusterId);
            if (clusterNodes.isEmpty()) return true; // Cluster was removed since we started
            cluster = updateCompletion(cluster, clusterNodes);

            var current = new AllocatableResources(clusterNodes.not().retired(), nodeRepository()).advertisedResources();

            // Autoscale unless an autoscaling is already in progress
            Autoscaling autoscaling = null;
            if (cluster.target().resources().isEmpty() && !cluster.scalingInProgress()) {
                autoscaling = autoscaler.autoscale(application.get(), cluster, clusterNodes, enabled, logDetails);
                if (autoscaling.isPresent() || cluster.target().isEmpty()) // Ignore empty from recently started servers
                    cluster = cluster.withTarget(autoscaling);
            }

            // Always store any updates
            if (cluster != unchangedCluster)
                applications().put(application.get().with(cluster), lock);

            // Attempt to perform the autoscaling immediately, and log it regardless
            if (autoscaling != null && autoscaling.resources().isPresent() && !current.equals(autoscaling.resources().get())) {
                redeploy = true;
                logAutoscaling(current, autoscaling.resources().get(), applicationId, clusterNodes.not().retired());
                if (logDetails) {
                    log.info("autoscaling data for " + applicationId.toFullString() + ": "
                            + "\n\tmetrics().cpuCostPerQuery(): " + autoscaling.metrics().cpuCostPerQuery()
                            + "\n\tmetrics().queryRate(): " + autoscaling.metrics().queryRate()
                            + "\n\tmetrics().growthRateHeadroom(): " + autoscaling.metrics().growthRateHeadroom()
                            + "\n\tpeak(): " + autoscaling.peak().toString()
                            + "\n\tideal(): " + autoscaling.ideal().toString());
                }
            }
        }
        catch (ApplicationLockException e) {
            return false;
        }
        catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Illegal arguments for " + applicationId + " cluster " + clusterId, e);
        }
        if (redeploy) {
            try (MaintenanceDeployment deployment = new MaintenanceDeployment(applicationId, deployer, metric, nodeRepository())) {
                if (deployment.isValid())
                    deployment.activate();
            }
        }
        return true;
    }
@Test
    public void test_cd_autoscaling_test() {
        ApplicationId app1 = AutoscalingMaintainerTester.makeApplicationId("app1");
        ClusterSpec cluster1 = AutoscalingMaintainerTester.containerClusterSpec();
        NodeResources resources = new NodeResources(1, 4, 50, 1);
        ClusterResources min = new ClusterResources( 2, 1, resources);
        ClusterResources max = new ClusterResources(3, 1, resources);
        var capacity = Capacity.from(min, max);
        var tester = new AutoscalingMaintainerTester(new Zone(SystemName.cd, Environment.prod, RegionName.from("us-east3")),
                                                     new MockDeployer.ApplicationContext(app1, cluster1, capacity));
        ManualClock clock = tester.clock();

        tester.deploy(app1, cluster1, capacity);
        assertEquals(2,
                     tester.nodeRepository().nodes().list(Node.State.active)
                           .owner(app1)
                           .cluster(cluster1.id())
                           .size());

        autoscale(false, Duration.ofMinutes( 1), Duration.ofMinutes( 5), clock, app1, cluster1, tester);
        assertEquals(3,
                     tester.nodeRepository().nodes().list(Node.State.active)
                           .owner(app1)
                           .cluster(cluster1.id())
                           .size());
    }