Skip to content

Commit

Permalink
refactor: Introduced core and cli subprojects
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Ruaux committed Apr 21, 2023
1 parent 55bc8d4 commit be6cba7
Show file tree
Hide file tree
Showing 72 changed files with 622 additions and 3,598 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ hs_err_pid*.log
*.iml
.vscode
/README.html
/spring-shell.log
1 change: 1 addition & 0 deletions core/redis-smart-cache-core/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
project_description=Redis Smart Cache Core
23 changes: 23 additions & 0 deletions core/redis-smart-cache-core/redis-smart-cache-core.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
dependencies {
implementation group: 'com.redis', name: 'lettucemod', version: lettucemodVersion
implementation 'org.springframework:spring-beans'
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-properties'
implementation group: 'io.airlift', name: 'units', version: airliftVersion
implementation 'io.micrometer:micrometer-registry-jmx'
implementation group: 'com.redis', name: 'micrometer-registry-redis', version: micrometerRedisVersion
testImplementation group: 'org.awaitility', name: 'awaitility', version: awaitilityVersion
testImplementation group: 'com.redis.testcontainers', name: 'testcontainers-redis-junit', version: testcontainersRedisVersion
}

bootJar {
enabled = false
}

jar {
archiveClassifier = ''
}

compileJava {
options.release = 8
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.redis.smartcache.core;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.redis.lettucemod.util.ClientBuilder;
import com.redis.lettucemod.util.RedisURIBuilder;
import com.redis.smartcache.core.Config.RedisConfig;

import io.lettuce.core.AbstractRedisClient;
import io.lettuce.core.RedisURI;

public class ClientManager implements AutoCloseable {

private static final Logger log = Logger.getLogger(ClientManager.class.getName());

private final Map<Config, AbstractRedisClient> clients = new HashMap<>();

public AbstractRedisClient getClient(Config config) {
return clients.computeIfAbsent(config, this::client);
}

private AbstractRedisClient client(Config config) {
RedisURI redisURI = redisURI(config.getRedis());
log.log(Level.FINE, "Creating Redis client with URI {0}", redisURI);
return ClientBuilder.create(redisURI).cluster(config.getRedis().isCluster()).build();
}

private RedisURI redisURI(RedisConfig config) {
RedisURIBuilder builder = RedisURIBuilder.create();
builder.uri(config.getUri());
builder.username(config.getUsername());
builder.password(config.getPassword());
builder.ssl(config.isTls());
builder.sslVerifyMode(config.getTlsVerify());
return builder.build();
}

@Override
public void close() {
clients.values().forEach(c -> {
c.shutdown();
c.getResources().shutdown();
});
clients.clear();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.redis.smartcache.core;

public interface Fields {

public static final String METER_QUERY = "query";
public static final String TAG_ID = "id";
public static final String TAG_TABLE = "table";
public static final String TAG_SQL = "sql";
public static final String TAG_TYPE = "type";

}
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,8 @@ public KeyBuilder sub(String keyspace) {
return new KeyBuilder().withKeyspace(build(keyspace)).withSeparator(separator);
}

public static KeyBuilder of(Config config) {
return KeyBuilder.of(config.getName()).withSeparator(config.getRedis().getKeySeparator());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.redis.smartcache.core;

import java.io.IOException;
import java.util.Properties;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsSchema;

public class Mappers {

public static final String PROPERTY_PREFIX = "smartcache";
public static final String PROPERTY_PREFIX_DRIVER = PROPERTY_PREFIX + ".driver";
public static final String PROPERTY_PREFIX_REDIS = PROPERTY_PREFIX + ".redis";

private static final JavaPropsSchema PROPS_SCHEMA = JavaPropsSchema.emptySchema().withPrefix(PROPERTY_PREFIX);
private static final JavaPropsMapper PROPS_MAPPER = propsMapper();

private Mappers() {
}

public static JavaPropsMapper propsMapper() {
return JavaPropsMapper.builder().serializationInclusion(Include.NON_NULL)
.propertyNamingStrategy(PropertyNamingStrategies.KEBAB_CASE)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();
}

public static Properties properties(Config config) throws IOException {
return PROPS_MAPPER.writeValueAsProperties(config, PROPS_SCHEMA);
}

public static Config config(Properties properties) throws IOException {
return PROPS_MAPPER.readPropertiesAs(properties, PROPS_SCHEMA, Config.class);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package com.redis.smartcache.core;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import com.redis.lettucemod.api.StatefulRedisModulesConnection;
import com.redis.lettucemod.util.RedisModulesUtils;
import com.redis.micrometer.RediSearchMeterRegistry;
import com.redis.micrometer.RediSearchRegistryConfig;
import com.redis.micrometer.RedisRegistryConfig;
import com.redis.micrometer.RedisTimeSeriesMeterRegistry;

import io.lettuce.core.AbstractRedisClient;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.composite.CompositeMeterRegistry;
import io.micrometer.core.instrument.config.MeterFilter;
import io.micrometer.core.instrument.simple.SimpleConfig;
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
import io.micrometer.jmx.JmxConfig;
import io.micrometer.jmx.JmxMeterRegistry;

public class MeterRegistryManager implements AutoCloseable {

private static final Logger log = Logger.getLogger(MeterRegistryManager.class.getName());

public static final String KEYSPACE_METRICS = "metrics";

private final ClientManager clientManager;
private final Map<Config, MeterRegistry> registries = new HashMap<>();

public MeterRegistryManager(ClientManager clientManager) {
this.clientManager = clientManager;
}

public MeterRegistry getRegistry(Config config) {
return registries.computeIfAbsent(config, this::meterRegistry);
}

private MeterRegistry meterRegistry(Config config) {
switch (config.getMetrics().getRegistry()) {
case JMX:
return jmxMeterRegistry(config);
case REDIS:
return redisMeterRegistry(config);
default:
return simpleMeterRegistry(config);
}
}

private SimpleMeterRegistry simpleMeterRegistry(Config config) {
Duration step = step(config);
return new SimpleMeterRegistry(new SimpleConfig() {

@Override
public String get(String key) {
return null;
}

@Override
public Duration step() {
return step;
}

}, Clock.SYSTEM);
}

private JmxMeterRegistry jmxMeterRegistry(Config config) {
Duration step = step(config);
return new JmxMeterRegistry(new JmxConfig() {

@Override
public String get(String key) {
return null;
}

@Override
public Duration step() {
return step;
}

@Override
public String domain() {
return config.getName();
}

}, Clock.SYSTEM);
}

private Duration duration(io.airlift.units.Duration duration) {
return Duration.ofMillis(duration.toMillis());
}

private Duration step(Config config) {
return duration(config.getMetrics().getStep());
}

private MeterRegistry redisMeterRegistry(Config config) {
AbstractRedisClient client = clientManager.getClient(config);
StatefulRedisModulesConnection<String, String> connection = RedisModulesUtils.connection(client);
try {
connection.sync().ftList();
} catch (Exception e) {
// Looks like we don't have Redis Modules
log.info("No RediSearch found, downgrading to simple meter registry");
return simpleMeterRegistry(config);
}
log.fine("Creating meter registry");
Duration step = step(config);
KeyBuilder keyBuilder = KeyBuilder.of(config);
String tsKeyspace = keyBuilder.build(KEYSPACE_METRICS);
RedisTimeSeriesMeterRegistry tsRegistry = new RedisTimeSeriesMeterRegistry(new RedisRegistryConfig() {

@Override
public String get(String key) {
return null;
}

@Override
public String keyspace() {
return tsKeyspace;
}

@Override
public String keySeparator() {
return keyBuilder.separator();
}

@Override
public Duration step() {
return step;
}

@Override
public boolean enabled() {
return config.getMetrics().isEnabled();
}

}, Clock.SYSTEM, client);
tsRegistry.config().meterFilter(MeterFilter.ignoreTags(Fields.TAG_SQL, Fields.TAG_TABLE));
RediSearchMeterRegistry searchRegistry = new RediSearchMeterRegistry(new RediSearchRegistryConfig() {

@Override
public String get(String key) {
return null;
}

@Override
public String keyspace() {
return keyBuilder.keyspace().orElse(null);
}

@Override
public String keySeparator() {
return keyBuilder.separator();
}

@Override
public Duration step() {
return step;
}

@Override
public String[] nonKeyTags() {
return new String[] { Fields.TAG_SQL, Fields.TAG_TABLE, Fields.TAG_TYPE };
}

@Override
public String indexPrefix() {
return keyBuilder.keyspace().orElse(null);
}

@Override
public String indexSuffix() {
return "idx";
}

@Override
public boolean enabled() {
return config.getMetrics().isEnabled();
}

}, Clock.SYSTEM, client);
searchRegistry.config().meterFilter(MeterFilter.acceptNameStartsWith(Fields.METER_QUERY))
.meterFilter(MeterFilter.deny());
return new CompositeMeterRegistry().add(tsRegistry).add(searchRegistry);
}

@Override
public void close() throws Exception {
registries.values().forEach(MeterRegistry::close);
registries.clear();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.redis.smartcache.core;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
import com.redis.smartcache.core.Config.RulesetConfig;

import io.lettuce.core.AbstractRedisClient;

public class RulesetManager implements AutoCloseable {

public static final String KEY_CONFIG = "config";

private final JavaPropsMapper mapper = Mappers.propsMapper();
private final Map<Config, ConfigManager<RulesetConfig>> configManagers = new HashMap<>();
private final ClientManager clientManager;

public RulesetManager(ClientManager clientManager) {
this.clientManager = clientManager;
}

public RulesetConfig getRuleset(Config config) {
return configManagers.computeIfAbsent(config, this::createConfigManager).get();
}

private ConfigManager<RulesetConfig> createConfigManager(Config config) {
AbstractRedisClient client = clientManager.getClient(config);
String key = KeyBuilder.of(config).build(KEY_CONFIG);
RulesetConfig ruleset = config.getRuleset();
StreamConfigManager<RulesetConfig> configManager = new StreamConfigManager<>(client, key, ruleset, mapper);
try {
configManager.start();
} catch (IOException e) {
throw new IllegalStateException("Could not start config manager", e);
}
return configManager;
}

@Override
public void close() throws Exception {
for (ConfigManager<RulesetConfig> configManager : configManagers.values()) {
configManager.close();
}
configManagers.clear();
}

}
Loading

0 comments on commit be6cba7

Please sign in to comment.