public static Recommendation makeRecommendation()

in src/main/java/com/google/cloud/run/kafkascaler/CpuScaling.java [50:109]


  public static Recommendation makeRecommendation(
      MetricTarget cpuTarget,
      List<MetricsService.InstanceCountUtilization> instanceCountUtilizations) {
    // Convert to fractions to ensure consistent units.
    double targetCpuUtilization = cpuTarget.averageUtilization() / 100.0;
    double activationUtilization = cpuTarget.activationThreshold() / 100.0;

    if (targetCpuUtilization < 0 || targetCpuUtilization > 1) {
      throw new IllegalArgumentException(
          "Target CPU utilization must be between 0 and 1 but was set to " + targetCpuUtilization);
    }
    if (instanceCountUtilizations == null || instanceCountUtilizations.isEmpty()) {
      logger.atInfo().log("[CPU] Scaling inactive, no data points found");
      return new Recommendation(false, 0);
    }

    double upperTolerance = (1.0 + cpuTarget.tolerance()) * targetCpuUtilization;
    double lowerTolerance = (1.0 - cpuTarget.tolerance()) * targetCpuUtilization;

    // Track this field solely for logging
    double utilizationSum = 0;

    double recommendationSum = 0;
    int numDataPoints = 0;
    for (MetricsService.InstanceCountUtilization dataPoint : instanceCountUtilizations) {
      if (dataPoint.utilization() > 1
          || dataPoint.utilization() < 0
          || dataPoint.instanceCount() < 0) {
        logger.atFine().log(
            "Ignoring invalid instance count-utilization data point: %s", dataPoint);
        continue;
      }

      // Sum up recommendations and utilizations to take an average below.
      if (dataPoint.utilization() >= lowerTolerance && dataPoint.utilization() <= upperTolerance) {
        recommendationSum += dataPoint.instanceCount();
      } else {
        recommendationSum +=
            dataPoint.instanceCount() * (dataPoint.utilization() / targetCpuUtilization);
      }
      utilizationSum += dataPoint.utilization();
      numDataPoints++;
    }

    int recommendedInstanceCount = (int) Math.ceil(recommendationSum / numDataPoints);
    double averageUtilization = utilizationSum / numDataPoints;
    logger.atInfo().log(
        "[CPU] Average utilization: %.3f, upper tolerance %.3f, lower tolerance %.3f",
        averageUtilization, upperTolerance, lowerTolerance);

    if (averageUtilization > activationUtilization) {
      logger.atInfo().log("[CPU] Recommended instance count: %d", recommendedInstanceCount);
      return new Recommendation(true, recommendedInstanceCount);
    } else {
      logger.atInfo().log(
          "[CPU] Scaling inactive. Average utilization: %.3f, activation threshold: %.3f",
          averageUtilization, activationUtilization);
      return new Recommendation(false, 0);
    }
  }