Skip to content

Commit

Permalink
feat: Added demo application
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Ruaux committed Jul 20, 2022
1 parent b8d3979 commit d5a922f
Show file tree
Hide file tree
Showing 19 changed files with 8,263 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.redis.sidecar;

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

import com.redis.micrometer.RedisTimeSeriesConfig;
import com.redis.micrometer.RedisTimeSeriesMeterRegistry;

import io.lettuce.core.AbstractRedisClient;
import io.micrometer.core.instrument.Clock;
import io.micrometer.core.instrument.MeterRegistry;

public class MeterRegistryManager {

private final Map<AbstractRedisClient, MeterRegistry> registries = new HashMap<>();

public MeterRegistry getRegistry(AbstractRedisClient redisClient, Config config) {
if (!registries.containsKey(redisClient)) {
registries.put(redisClient, registry(redisClient, config));
}
return registries.get(redisClient);
}

private MeterRegistry registry(AbstractRedisClient redisClient, Config config) {
return new RedisTimeSeriesMeterRegistry(new RedisTimeSeriesConfig() {

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

@Override
public String uri() {
return config.getRedis().getUri();
}

@Override
public boolean cluster() {
return config.getRedis().isCluster();
}

@Override
public String keyspace() {
return config.getRedis().key("metrics");
}

@Override
public Duration step() {
return Duration.ofSeconds(config.getMetricsStep());
}

}, Clock.SYSTEM, redisClient);
}

public void clear() {
registries.forEach((k, v) -> v.close());
registries.clear();
}

}
40 changes: 40 additions & 0 deletions demos/redis-sidecar-spring-demo/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
version: "2.2"

services:
mysql:
image: mysql:latest
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=
- MYSQL_ALLOW_EMPTY_PASSWORD=true
- MYSQL_USER=sidecar
- MYSQL_PASSWORD=sidecar
- MYSQL_DATABASE=sidecar
volumes:
- "./conf.d:/etc/mysql/conf.d:ro"

postgres:
image: postgres:14.1
ports:
- 5432:5432
environment:
- POSTGRES_PASSWORD=sidecar
- POSTGRES_USER=sidecar
- POSTGRES_DB=sidecar

grafana:
image: grafana/grafana
hostname: grafana
container_name: grafana
ports:
- 3000:3000
environment:
- GF_INSTALL_PLUGINS=redis-app

redis:
image: redis/redis-stack-server
hostname: redis
container_name: redis
ports:
- 6379:6379
1 change: 1 addition & 0 deletions demos/redis-sidecar-spring-demo/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
project_description=Redis-Sidecar Demo
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
dependencies {
implementation project(':redis-sidecar-jdbc')
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly project(':redis-sidecar-jdbc')
implementation group: 'com.redis', name: 'spring-lettucemod', version: lettucemodVersion
runtimeOnly 'mysql:mysql-connector-java'
runtimeOnly 'org.postgresql:postgresql'
runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.redis.sidecar.springdemo;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConfigurationProperties(prefix = "sidecar")
public class Config {

private int rows;
private int maxQuantity;
private int batchSize;
private int orderSpread;

public int getOrderSpread() {
return orderSpread;
}

public void setOrderSpread(int orderSpread) {
this.orderSpread = orderSpread;
}

public int getBatchSize() {
return batchSize;
}

public void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}

public int getRows() {
return rows;
}

public void setRows(int rows) {
this.rows = rows;
}

public int getMaxQuantity() {
return maxQuantity;
}

public void setMaxQuantity(int maxQuantity) {
this.maxQuantity = maxQuantity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.redis.sidecar.springdemo;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;

@Component
@ConditionalOnExpression(value = "#{ '${database}' matches 'postgres' }")
public class PostgresDataLoader {

private static Logger log = LoggerFactory.getLogger(PostgresDataLoader.class);

private static final List<String> CUSTOMER_IDS = Arrays.asList("ALFKI", "ANATR", "ANTON", "AROUT", "BERGS", "BLAUS",
"BLONP", "BOLID", "BONAP", "BOTTM", "BSBEV", "CACTU", "CENTC", "CHOPS", "COMMI", "CONSH", "DRACD", "DUMON",
"EASTC", "ERNSH", "FAMIA", "FISSA", "FOLIG", "FOLKO", "FRANK", "FRANR", "FRANS", "FURIB", "GALED", "GODOS",
"GOURL", "GREAL", "GROSR", "HANAR", "HILAA", "HUNGC", "HUNGO", "ISLAT", "KOENE", "LACOR", "LAMAI", "LAUGB",
"LAZYK", "LEHMS", "LETSS", "LILAS", "LINOD", "LONEP", "MAGAA", "MAISD", "MEREP", "MORGK", "NORTS", "OCEAN",
"OLDWO", "OTTIK", "PARIS", "PERIC", "PICCO", "PRINI", "QUEDE", "QUEEN", "QUICK", "RANCH", "RATTC", "REGGC",
"RICAR", "RICSU", "ROMEY", "SANTG", "SAVEA", "SEVES", "SIMOB", "SPECD", "SPLIR", "SUPRD", "THEBI", "THECR",
"TOMSP", "TORTU", "TRADH", "TRAIH", "VAFFE", "VICTE", "VINET", "WANDK", "WARTH", "WELLI", "WHITC", "WILMK",
"WOLZA");

private static final int ORDER_ID_START = 20000;

private final Random random = new Random();
private final DataSource dataSource;
private final Config config;

public PostgresDataLoader(DataSource dataSource, Config config) {
this.dataSource = dataSource;
this.config = config;
}

@PostConstruct
public void execute() throws SQLException, IOException {
if (rowCount() == config.getRows()) {
log.info("Database already populated");
return;
}
String insertOrderSQL = "INSERT INTO orders VALUES (?, ?, ?, '1996-07-04', '1996-08-01', '1996-07-16', 3, 32.3800011, 'Vins et alcools Chevalier', '59 rue de l''Abbaye', 'Reims', NULL, '51100', 'France')";
String insertOrderDetailsSQL = "INSERT INTO order_details VALUES (?, ?, ?, ?, 0)";
try (Connection connection = dataSource.getConnection()) {
ScriptRunner scriptRunner = new ScriptRunner(connection);
scriptRunner.setAutoCommit(false);
scriptRunner.setStopOnError(true);
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("db/postgres/drop.sql")) {
scriptRunner.runScript(new InputStreamReader(inputStream));
}
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("db/postgres/schema.sql")) {
scriptRunner.runScript(new InputStreamReader(inputStream));
}
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("db/postgres/data.sql")) {
scriptRunner.runScript(new InputStreamReader(inputStream));
}
PreparedStatement orderStatement = connection.prepareStatement(insertOrderSQL);
PreparedStatement detailsStatement = connection.prepareStatement(insertOrderDetailsSQL);
log.info("Populating database with {} rows", config.getRows());
for (int index = 0; index < config.getRows(); index++) {
int orderId = ORDER_ID_START + index;
String customerId = CUSTOMER_IDS.get(random.nextInt(CUSTOMER_IDS.size()));
int employeeId = 1 + random.nextInt(9);
int productId = 1 + random.nextInt(77);
double price = random.nextDouble();
int quantity = random.nextInt(config.getMaxQuantity());

orderStatement.setInt(1, orderId);
orderStatement.setString(2, customerId);
orderStatement.setInt(3, employeeId);
orderStatement.addBatch();

detailsStatement.setInt(1, orderId);
detailsStatement.setInt(2, productId);
detailsStatement.setDouble(3, price);
detailsStatement.setInt(4, quantity);
detailsStatement.addBatch();

if (index % config.getBatchSize() == 0) {
orderStatement.executeBatch();
orderStatement.close();
orderStatement = connection.prepareStatement(insertOrderSQL);
detailsStatement.executeBatch();
detailsStatement.close();
detailsStatement = connection.prepareStatement(insertOrderDetailsSQL);
}
}
orderStatement.executeBatch();
orderStatement.close();
detailsStatement.executeBatch();
detailsStatement.close();
log.info("Inserted {} rows", rowCount());
}

}

private int rowCount() throws SQLException {
try (Connection connection = dataSource.getConnection();
Statement countStatement = connection.createStatement();
ResultSet countResultSet = countStatement.executeQuery("SELECT COUNT(*) FROM orders");) {
countResultSet.next();
return countResultSet.getInt(1);
} catch (SQLException e) {
return 0;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package com.redis.sidecar.springdemo;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Random;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

@Component
@ConditionalOnExpression(value = "#{ '${database}' matches 'postgres' }")
public class PostgresQueryExecutor implements DisposableBean {

private static Logger log = LoggerFactory.getLogger(PostgresQueryExecutor.class);

private static final int ORDER_ID_START = 20000;
private static final String QUERY = "SELECT * FROM orders o INNER JOIN order_details d ON o.order_id = d.order_id"
+ " INNER JOIN products p ON p.product_id = d.product_id"
+ " INNER JOIN customers c ON c.customer_id = o.customer_id"
+ " INNER JOIN employees e ON e.employee_id = o.employee_id"
+ " INNER JOIN employee_territories t ON t.employee_id = e.employee_id"
+ " INNER JOIN categories g ON g.category_id = p.category_id"
+ " WHERE o.order_id BETWEEN ? AND ?";

private final Random random = new Random();
private final DataSource sidecarDataSource;
private final Config config;
private final TaskExecutor taskExecutor;
private boolean stopped;

public PostgresQueryExecutor(DataSource sidecarDataSource, Config config, TaskExecutor taskExecutor) {
this.sidecarDataSource = sidecarDataSource;
this.config = config;
this.taskExecutor = taskExecutor;
}

@PostConstruct
public void executeQueries() {
taskExecutor.execute(new QueryTask(sidecarDataSource, config));
}

public void stop() {
this.stopped = true;
}

private class QueryTask implements Runnable {

private final DataSource dataSource;
private final Config config;

public QueryTask(DataSource dataSource, Config config) {
this.dataSource = dataSource;
this.config = config;
}

@Override
public void run() {
int executionCount = 0;
while (!isStopped()) {
int rowCount = 0;
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(QUERY)) {
int startOrder = ORDER_ID_START + random.nextInt(config.getOrderSpread());
statement.setInt(1, startOrder);
statement.setInt(2, startOrder + random.nextInt(config.getOrderSpread()));
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
for (int columnIndex = 1; columnIndex <= resultSet.getMetaData()
.getColumnCount(); columnIndex++) {
resultSet.getObject(columnIndex);
}
rowCount++;
}
}
executionCount++;
} catch (SQLException e) {
log.error("Could not run query", e);
}
if (executionCount % 100 == 0) {
log.info("Ran {} queries; #rows: {}", executionCount, rowCount);
}

}
}

private boolean isStopped() {
return stopped;
}
}

@Override
public void destroy() throws Exception {
this.stopped = true;
}

}
Loading

0 comments on commit d5a922f

Please sign in to comment.