Skip to content

Commit 243487e

Browse files
committed
Preventing scaling when more than 1 database present in sub, deterministic only scale down, health check endpoint
1 parent 683cd67 commit 243487e

File tree

9 files changed

+109
-18
lines changed

9 files changed

+109
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.redis.autoscaler;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import lombok.Data;
5+
6+
@Data
7+
@JsonIgnoreProperties(ignoreUnknown = true)
8+
public class DatabaseListResponse {
9+
private int accountId;
10+
private Subscripition[] subscription;
11+
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.redis.autoscaler;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import lombok.Data;
5+
6+
@Data
7+
@JsonIgnoreProperties(ignoreUnknown = true)
8+
public class Subscripition {
9+
private String subscriptionId;
10+
private int numberOfDatabases;
11+
private RedisCloudDatabase[] databases;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.redis.autoscaler.controllers;
2+
3+
import org.springframework.http.ResponseEntity;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
import org.springframework.web.bind.annotation.RestController;
6+
7+
@RestController
8+
public class HealthController {
9+
@GetMapping("/health")
10+
public ResponseEntity<String> health() {
11+
return ResponseEntity.ok("Healthy");
12+
}
13+
}

autoscaler/redis-cloud-autoscaler/src/main/java/com/redis/autoscaler/controllers/RulesController.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.redis.autoscaler.controllers;
22

3-
import com.redis.autoscaler.documents.RuleType;
43
import com.redis.autoscaler.documents.RuleRepository;
54
import com.redis.autoscaler.documents.Rule;
65
import com.redis.autoscaler.documents.TriggerType;
@@ -14,7 +13,6 @@
1413
import org.springframework.web.bind.annotation.*;
1514

1615
import java.io.IOException;
17-
import java.util.Objects;
1816
import java.util.Optional;
1917

2018
@RestController
@@ -31,14 +29,19 @@ public RulesController(RedisCloudDatabaseService redisCloudDatabaseService, Rule
3129
this.schedulingService = schedulingService;
3230
}
3331

32+
@GetMapping("/numDatabases")
33+
public HttpEntity<Integer> getNumDatabases() throws IOException, InterruptedException {
34+
return ResponseEntity.ok(redisCloudDatabaseService.getDatabaseCount());
35+
}
36+
37+
3438
@PostMapping
3539
public HttpEntity<Object> createRule(@RequestBody Rule rule) {
3640
LOG.info("Received request to create rule: {}", rule);
3741

38-
if(rule.getRuleType() == RuleType.IncreaseMemory || rule.getRuleType() == RuleType.DecreaseMemory) {
39-
if(!rule.isValid()) {
40-
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
41-
}
42+
String ruleValidityError = rule.getValidationError();
43+
if(!ruleValidityError.isEmpty()) {
44+
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ruleValidityError);
4245
}
4346

4447
LOG.info("Attempting to create rule: {}", rule);

autoscaler/redis-cloud-autoscaler/src/main/java/com/redis/autoscaler/documents/Rule.java

+31-8
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
import com.redis.om.spring.annotations.Document;
44
import com.redis.om.spring.annotations.Indexed;
55
import lombok.Data;
6+
import org.slf4j.Logger;
67
import org.springframework.data.annotation.Id;
78

89
@Document
910
@Data
1011
public class Rule {
12+
private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(Rule.class);
13+
1114
@Indexed
1215
protected String dbId;
1316

@@ -37,40 +40,60 @@ public String toString(){
3740
}
3841

3942

40-
public boolean isValid(){
43+
public String getValidationError(){
44+
LOG.info("Validating rule: {}", this);
45+
4146
if(this.ruleType == RuleType.IncreaseMemory){
4247
if(scaleType == ScaleType.Deterministic || scaleType == ScaleType.Step){
4348
if(scaleValue > scaleCeiling){
44-
return false;
49+
return "Scale value is greater than scale ceiling";
4550
}
4651

4752
}
4853

4954
if(scaleType == ScaleType.Deterministic) {
5055
if(!isMultipleOfPointOne()){
51-
return false;
56+
return "Memory Scale must be a multiple of 0.1";
5257
}
5358
}
5459
}
5560

5661
if(this.ruleType == RuleType.DecreaseMemory){
5762
if(scaleType == ScaleType.Deterministic){
5863
if(scaleValue < scaleFloor){
59-
return false;
64+
return "Scale value is less than scale floor";
6065
}
66+
} else {
67+
return "Non-deterministic Scale in Operations are not supported"; // non-deterministic decrease rules are not allowed
6168
}
6269

63-
if(scaleType == ScaleType.Deterministic) {
64-
if(!isMultipleOfPointOne()){
65-
return false;
70+
71+
}
72+
73+
if(this.ruleType == RuleType.IncreaseThroughput){
74+
if(scaleType == ScaleType.Deterministic || scaleType == ScaleType.Step){
75+
if(scaleValue > scaleCeiling){
76+
return "Scale value is greater than scale ceiling";
77+
}
78+
}
79+
}
80+
81+
if(this.ruleType == RuleType.DecreaseThroughput){
82+
if(scaleType == ScaleType.Deterministic ){
83+
if(scaleValue < scaleFloor){
84+
return "Scale value is less than scale floor";
6685
}
86+
} else {
87+
LOG.info("Non-deterministic decrease rules are not allowed: rule type: {}", ruleType);
88+
return "Non-deterministic Scale in Operations are not supported"; // non-deterministic decrease rules are not allowed
6789
}
6890
}
6991

70-
return true;
92+
return "";
7193
}
7294

7395
protected boolean isMultipleOfPointOne() {
96+
LOG.info("Validating scale value: {}", scaleValue);
7497
double compValue = scaleValue - Math.floor(scaleValue);
7598
double epsilon = 1e-9; // Small tolerance for floating-point precision
7699
return Math.abs(compValue % 0.1) < epsilon;

autoscaler/redis-cloud-autoscaler/src/main/java/com/redis/autoscaler/services/RedisCloudDatabaseService.java

+28
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,27 @@ public RedisCloudDatabaseService(HttpClient httpClient, HttpClientConfig httpReq
3636
this.config = config;
3737
}
3838

39+
public int getDatabaseCount() throws IOException, InterruptedException {
40+
URI uri = URI.create(String.format("%s/subscriptions/%s/databases", Constants.REDIS_CLOUD_URI_BASE, config.getSubscriptionId()));
41+
HttpRequest request = httpClientConfig.requestBuilder()
42+
.uri(uri)
43+
.GET().build();
44+
45+
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
46+
47+
if(response.statusCode() != 200){
48+
throw new RuntimeException(String.format("Failed to fetch database count on %s", uri.toString()));
49+
}
50+
51+
DatabaseListResponse databaseListResponse = objectMapper.readValue(response.body(), DatabaseListResponse.class);
52+
if(databaseListResponse.getSubscription().length == 0){
53+
LOG.warn("No subscriptions found for subscription id: {}", config.getSubscriptionId());
54+
return 0;
55+
}
56+
57+
return databaseListResponse.getSubscription()[0].getDatabases().length;
58+
}
59+
3960
public RedisCloudDatabase getDatabase(String dbId) throws IOException, InterruptedException {
4061

4162
URI uri = URI.create(String.format("%s/subscriptions/%s/databases/%s", Constants.REDIS_CLOUD_URI_BASE, config.getSubscriptionId(), dbId));
@@ -63,6 +84,13 @@ public Optional<Task> applyRule(Rule rule) throws IOException, InterruptedExcept
6384
return Optional.empty();
6485
}
6586

87+
int numDatabases = getDatabaseCount();
88+
if(numDatabases > 1){
89+
LOG.warn("Database count for subscription {} is greater than 1, using autoscaler is not supported, skipping rule: {}", config.getSubscriptionId(), rule);
90+
return Optional.empty();
91+
}
92+
93+
6694
ScaleRequest scaleRequest;
6795
switch (rule.getRuleType()){
6896
case IncreaseMemory, DecreaseMemory -> {

main.tf

+2-2
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ resource "null_resource" "build_app" {
183183
}
184184

185185
provisioner "file" {
186-
source = "./autoscaler/redis-cloud-autoscaler/build/libs/redis-cloud-autoscaler.jar"
186+
source = "./autoscaler/redis-cloud-autoscaler/build/libs/redis-cloud-autoscaler-0.0.2.jar"
187187
destination = "autoscaler.jar"
188188
}
189189

@@ -212,7 +212,7 @@ resource "null_resource" "build_app" {
212212
"echo 'Environment=REDIS_PASSWORD=${rediscloud_subscription_database.autoscale-database.password}' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
213213
"echo 'Environment=REDIS_CLOUD_API_KEY=${var.redis_cloud_api_key}' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
214214
"echo 'Environment=REDIS_CLOUD_ACCOUNT_KEY=${var.redis_cloud_account_key}' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
215-
"echo 'Environment=REDIS_CLOUD_SUBSCRIPTION_ID=${rediscloud_subscription_database.autoscale-database.id}' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
215+
"echo 'Environment=REDIS_CLOUD_SUBSCRIPTION_ID=${rediscloud_subscription.autoscaling_sub.id}' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
216216
"echo 'Environment=ALERT_MANAGER_HOST=${google_compute_instance.autoscale-vm-prometheus.network_interface[0].access_config[0].nat_ip}' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
217217
"echo 'Environment=ALERT_MANAGER_PORT=9093' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",
218218
"echo 'ExecStart=/usr/bin/java -jar /usr/local/bin/autoscaler.jar' | sudo tee -a /etc/systemd/system/autoscaler.service > /dev/null",

quickstart/docker/docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ services:
1313
- autoscaler
1414
env_file:
1515
- .env
16-
volumes:
16+
volumes:
1717
- ./prometheus/alertmanager.yml:/etc/alertmanager/alertmanager.yml
1818
ports:
1919
- 9093:9093

redeploy-autoscaler.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22

33
./gradlew clean bootjar
4-
gcloud compute scp ./autoscaler/redis-cloud-autoscaler/build/libs/redis-cloud-autoscaler.jar autoscaler-vm:~/autoscaler.jar --zone=us-east1-b
4+
gcloud compute scp ./autoscaler/redis-cloud-autoscaler/build/libs/redis-cloud-autoscaler-0.0.2.jar autoscaler-vm:~/autoscaler.jar --zone=us-east1-b
55
# run command to move the jar to /usr/local/bin/autoscaler.jar, change owner to autoscaler, and restart the autoscaler service
66
gcloud compute ssh --zone=us-east1-b autoscaler-vm --command "sudo cp ~/autoscaler.jar /usr/local/bin/autoscaler.jar && sudo chown autoscaler:autoscaler /usr/local/bin/autoscaler.jar && sudo systemctl restart autoscaler"

0 commit comments

Comments
 (0)