From c5777644851f1a3b4693314ef5f0c44e3aef0f18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=20G=C3=B3mez?= Date: Mon, 13 Nov 2023 11:40:43 +0100 Subject: [PATCH] chore: add all servers to docker (#85) * chore: add all servers to docker * chore: add all servers to docker * chore: wait until elastic is up * ci: add test server to run the tests * ci: use specific docker-compose for ci --- Makefile | 8 +- apps/main/resources/.env | 16 ++-- docker-compose.ci.yml | 55 ++++++++++++ docker-compose.yml | 86 +++++++++++++++---- .../BackofficeElasticsearchConfiguration.java | 47 +++++----- src/mooc/main/resources/database/mooc.sql | 1 + .../hibernate/CoursesCounter.hbm.xml | 2 +- .../persistence/hibernate/CustomTypes.hbm.xml | 8 -- .../main/tv/codely/shared/domain/Utils.java | 23 +++++ .../DomainEventSubscriberInformation.java | 2 +- .../HibernateConfigurationFactory.java | 16 ++-- .../hibernate/JsonListType.java | 56 +++++------- 12 files changed, 223 insertions(+), 97 deletions(-) create mode 100755 docker-compose.ci.yml delete mode 100644 src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml diff --git a/Makefile b/Makefile index 959d60c7..c312ce16 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,25 @@ all: build start: - @docker compose up -d + @docker-compose -f docker-compose.ci.yml up -d build: @./gradlew build --warning-mode all lint: - @docker exec codelytv-ddd_example-java ./gradlew spotlessCheck + @docker exec codely-java_ddd_example-test_server ./gradlew spotlessCheck run-tests: @./gradlew test --warning-mode all test: - @docker exec codelytv-ddd_example-java ./gradlew test --warning-mode all + @docker exec codely-java_ddd_example-test_server ./gradlew test --warning-mode all run: @./gradlew :run ping-mysql: - @docker exec codelytv-java_ddd_example-mysql mysqladmin --user=root --password= --host "127.0.0.1" ping --silent + @docker exec codely-java_ddd_example-mysql mysqladmin --user=root --password= --host "127.0.0.1" ping --silent # Start the app start-mooc_backend: diff --git a/apps/main/resources/.env b/apps/main/resources/.env index ac2f8345..cd58c259 100644 --- a/apps/main/resources/.env +++ b/apps/main/resources/.env @@ -1,8 +1,8 @@ # MOOC # #--------------------------------# -MOOC_BACKEND_SERVER_PORT=8081 +MOOC_BACKEND_SERVER_PORT=8030 # MySql -MOOC_DATABASE_HOST=codelytv-java_ddd_example-mysql +MOOC_DATABASE_HOST=codely-java_ddd_example-mysql MOOC_DATABASE_PORT=3306 MOOC_DATABASE_NAME=mooc MOOC_DATABASE_USER=root @@ -10,25 +10,25 @@ MOOC_DATABASE_PASSWORD= # BACKOFFICE # #--------------------------------# -BACKOFFICE_FRONTEND_SERVER_PORT=8090 -BACKOFFICE_BACKEND_SERVER_PORT=8091 +BACKOFFICE_BACKEND_SERVER_PORT=8040 +BACKOFFICE_FRONTEND_SERVER_PORT=8041 # MySql -BACKOFFICE_DATABASE_HOST=codelytv-java_ddd_example-mysql +BACKOFFICE_DATABASE_HOST=codely-java_ddd_example-mysql BACKOFFICE_DATABASE_PORT=3306 BACKOFFICE_DATABASE_NAME=backoffice BACKOFFICE_DATABASE_USER=root BACKOFFICE_DATABASE_PASSWORD= # Elasticsearch -BACKOFFICE_ELASTICSEARCH_HOST=codelytv-java_ddd_example-elasticsearch +BACKOFFICE_ELASTICSEARCH_HOST=codely-java_ddd_example-elasticsearch BACKOFFICE_ELASTICSEARCH_PORT=9200 BACKOFFICE_ELASTICSEARCH_INDEX_PREFIX=backoffice # COMMON # #--------------------------------# # RabbitMQ -RABBITMQ_HOST=codelytv-java_ddd_example-rabbitmq +RABBITMQ_HOST=codely-java_ddd_example-rabbitmq RABBITMQ_PORT=5672 -RABBITMQ_LOGIN=codelytv +RABBITMQ_LOGIN=codely RABBITMQ_PASSWORD=c0d3ly RABBITMQ_EXCHANGE=domain_events RABBITMQ_MAX_RETRIES=5 diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml new file mode 100755 index 00000000..654ffd12 --- /dev/null +++ b/docker-compose.ci.yml @@ -0,0 +1,55 @@ +version: '3' + +services: + shared_mysql: + container_name: codely-java_ddd_example-mysql + image: mysql:8 + platform: linux/amd64 + ports: + - "3306:3306" + environment: + - MYSQL_ROOT_PASSWORD= + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + entrypoint: + sh -c " + echo 'CREATE DATABASE IF NOT EXISTS mooc;CREATE DATABASE IF NOT EXISTS backoffice;' > /docker-entrypoint-initdb.d/init.sql; + /usr/local/bin/docker-entrypoint.sh --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + " + command: ["--default-authentication-plugin=mysql_native_password"] + + shared_rabbitmq: + container_name: codely-java_ddd_example-rabbitmq + image: 'rabbitmq:3.7-management' + platform: linux/amd64 + restart: unless-stopped + ports: + - "5630:5672" + - "8090:15672" + environment: + - RABBITMQ_DEFAULT_USER=codely + - RABBITMQ_DEFAULT_PASS=c0d3ly + + backoffice_elasticsearch: + container_name: codely-java_ddd_example-elasticsearch + image: 'elasticsearch:6.8.4' + platform: linux/amd64 + restart: unless-stopped + ports: + - "9300:9300" + - "9200:9200" + environment: + - discovery.type=single-node + + test_server_java: + container_name: codely-java_ddd_example-test_server + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + volumes: + - .:/app:delegated + depends_on: + - shared_mysql + - shared_rabbitmq + - backoffice_elasticsearch + tty: true diff --git a/docker-compose.yml b/docker-compose.yml index 4d6015c0..3da6fcb7 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,8 +1,8 @@ version: '3' services: - mysql: - container_name: codelytv-java_ddd_example-mysql + shared_mysql: + container_name: codely-java_ddd_example-mysql image: mysql:8 platform: linux/amd64 ports: @@ -17,8 +17,8 @@ services: " command: ["--default-authentication-plugin=mysql_native_password"] - rabbitmq: - container_name: codelytv-java_ddd_example-rabbitmq + shared_rabbitmq: + container_name: codely-java_ddd_example-rabbitmq image: 'rabbitmq:3.7-management' platform: linux/amd64 restart: unless-stopped @@ -26,11 +26,11 @@ services: - "5630:5672" - "8090:15672" environment: - - RABBITMQ_DEFAULT_USER=codelytv + - RABBITMQ_DEFAULT_USER=codely - RABBITMQ_DEFAULT_PASS=c0d3ly - elasticsearch: - container_name: codelytv-java_ddd_example-elasticsearch + backoffice_elasticsearch: + container_name: codely-java_ddd_example-elasticsearch image: 'elasticsearch:6.8.4' platform: linux/amd64 restart: unless-stopped @@ -40,20 +40,74 @@ services: environment: - discovery.type=single-node - java: - container_name: codelytv-ddd_example-java + backoffice_backend_server_java: + container_name: codely-java_ddd_example-backoffice_backend_server build: context: . dockerfile: Dockerfile restart: unless-stopped - platform: linux/amd64 ports: - - "8030:8080" + - "8040:8040" volumes: - .:/app:delegated - env_file: - - .env - tty: true + - backoffice_backend_gradle_cache:/app/.gradle + depends_on: + - shared_mysql + - shared_rabbitmq + - backoffice_elasticsearch + command: ["./gradlew", "bootRun", "--args", "backoffice_backend server"] + + backoffice_frontend_server_java: + container_name: codely-java_ddd_example-backoffice_frontend_server + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + ports: + - "8041:8041" + volumes: + - .:/app:delegated + - backoffice_frontend_gradle_cache:/app/.gradle + depends_on: + - shared_mysql + - shared_rabbitmq + - backoffice_elasticsearch + command: ["./gradlew", "bootRun", "--args", "backoffice_frontend server"] + + mooc_backend_server_java: + container_name: codely-java_ddd_example-mooc_backend_server + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + ports: + - "8030:8030" + volumes: + - .:/app:delegated + - mooc_backend_gradle_cache:/app/.gradle depends_on: - - mysql - - rabbitmq + - shared_mysql + - shared_rabbitmq + - backoffice_elasticsearch + command: ["./gradlew", "bootRun", "--args", "mooc_backend server"] + + test_server_java: + container_name: codely-java_ddd_example-test_server + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + volumes: + - .:/app:delegated + - test_gradle_cache:/app/.gradle + depends_on: + - shared_mysql + - shared_rabbitmq + - backoffice_elasticsearch + tty: true + +volumes: + backoffice_backend_gradle_cache: + backoffice_frontend_gradle_cache: + mooc_backend_gradle_cache: + test_gradle_cache: diff --git a/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java b/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java index 582309c9..98c0f1ad 100644 --- a/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java +++ b/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java @@ -10,6 +10,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; +import tv.codely.shared.domain.Utils; import tv.codely.shared.infrastructure.config.Parameter; import tv.codely.shared.infrastructure.config.ParameterNotExist; import tv.codely.shared.infrastructure.elasticsearch.ElasticsearchClient; @@ -29,27 +30,33 @@ public BackofficeElasticsearchConfiguration(Parameter config, ResourcePatternRes } @Bean - public ElasticsearchClient elasticsearchClient() throws ParameterNotExist, IOException { - ElasticsearchClient client = new ElasticsearchClient( - new RestHighLevelClient( - RestClient.builder( - new HttpHost( - config.get("BACKOFFICE_ELASTICSEARCH_HOST"), - config.getInt("BACKOFFICE_ELASTICSEARCH_PORT"), - "http" - ) - ) - ), - RestClient.builder( - new HttpHost( - config.get("BACKOFFICE_ELASTICSEARCH_HOST"), - config.getInt("BACKOFFICE_ELASTICSEARCH_PORT"), - "http" - )).build(), - config.get("BACKOFFICE_ELASTICSEARCH_INDEX_PREFIX") - ); + public ElasticsearchClient elasticsearchClient() throws ParameterNotExist, Exception { + ElasticsearchClient client = new ElasticsearchClient( + new RestHighLevelClient( + RestClient.builder( + new HttpHost( + config.get("BACKOFFICE_ELASTICSEARCH_HOST"), + config.getInt("BACKOFFICE_ELASTICSEARCH_PORT"), + "http" + ) + ) + ), + RestClient.builder( + new HttpHost( + config.get("BACKOFFICE_ELASTICSEARCH_HOST"), + config.getInt("BACKOFFICE_ELASTICSEARCH_PORT"), + "http" + )).build(), + config.get("BACKOFFICE_ELASTICSEARCH_INDEX_PREFIX") + ); - generateIndexIfNotExists(client, "backoffice"); + Utils.retry(10, 10000, () -> { + try { + generateIndexIfNotExists(client, "backoffice"); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); return client; } diff --git a/src/mooc/main/resources/database/mooc.sql b/src/mooc/main/resources/database/mooc.sql index 0a92a816..6cc6def8 100644 --- a/src/mooc/main/resources/database/mooc.sql +++ b/src/mooc/main/resources/database/mooc.sql @@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS courses_counter ( ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci; +INSERT IGNORE INTO courses_counter (id, total, existing_courses) VALUES ('efbaff16-8fcd-4689-9fc9-ec545d641c46', 0, '[]'); CREATE TABLE IF NOT EXISTS steps ( id CHAR(36) NOT NULL, diff --git a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml b/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml index 575782d9..8ea74820 100644 --- a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml +++ b/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml @@ -16,7 +16,7 @@ - + tv.codely.mooc.courses.domain.CourseId diff --git a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml b/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml deleted file mode 100644 index f80d380b..00000000 --- a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/src/shared/main/tv/codely/shared/domain/Utils.java b/src/shared/main/tv/codely/shared/domain/Utils.java index b0b26f75..53dbc3ea 100644 --- a/src/shared/main/tv/codely/shared/domain/Utils.java +++ b/src/shared/main/tv/codely/shared/domain/Utils.java @@ -47,4 +47,27 @@ public static String toCamel(String text) { public static String toCamelFirstLower(String text) { return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, text); } + + public static void retry(int numberOfRetries, long waitTimeInMillis, Runnable operation) throws Exception { + for (int i = 0; i < numberOfRetries; i++) { + try { + operation.run(); + return; // Success, exit the method + } catch (Exception ex) { + System.out.println("Retry " + (i + 1) + "/" + numberOfRetries + " fail. Retrying…"); + if (i >= numberOfRetries - 1) { + throw ex; + } + + try { + Thread.sleep(waitTimeInMillis); + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + + throw new Exception("Operation interrupted while retrying", ie); + } + } + } + } + } diff --git a/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java b/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java index da88eb38..e14d3d2c 100644 --- a/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java +++ b/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java @@ -44,6 +44,6 @@ public List> subscribedEvents() { } public String formatRabbitMqQueueName() { - return String.format("codelytv.%s.%s.%s", contextName(), moduleName(), Utils.toSnake(className())); + return String.format("codely.%s.%s.%s", contextName(), moduleName(), Utils.toSnake(className())); } } diff --git a/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java b/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java index 14551810..2dbd1bad 100644 --- a/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java +++ b/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java @@ -110,13 +110,19 @@ private List subdirectoriesFor(String contextName) { } private String[] mappingFilesIn(String path) { - String[] files = new File(path).list((current, name) -> new File(current, name).getName().contains(".hbm.xml")); + List fileList = new ArrayList<>(); - if (null == files) { - return new String[0]; - } + String[] hbmFiles = new File(path).list((current, name) -> new File(current, name).getName().contains(".hbm.xml")); + String[] ormFiles = new File(path).list((current, name) -> new File(current, name).getName().contains(".orm.xml")); + + if (hbmFiles != null) { + fileList.addAll(Arrays.asList(hbmFiles)); + } + if (ormFiles != null) { + fileList.addAll(Arrays.asList(ormFiles)); + } - return files; + return fileList.toArray(new String[0]); } private Properties hibernateProperties() { diff --git a/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java b/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java index 024f880d..188dd98b 100644 --- a/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java +++ b/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java @@ -19,7 +19,6 @@ import java.util.*; public class JsonListType implements UserType, DynamicParameterizedType { - private static final int[] SQL_TYPES = new int[]{Types.LONGVARCHAR}; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private JavaType valueType = null; private Class classType = null; @@ -44,24 +43,6 @@ public int hashCode(Object x) throws HibernateException { return Objects.hashCode(x); } - @Override - public Object nullSafeGet( - ResultSet resultSet, - int i, - SharedSessionContractImplementor sharedSessionContractImplementor, - Object o - ) throws SQLException { - try { - String json = resultSet.getString(i); - if (json == null) { - return null; - } - return OBJECT_MAPPER.readValue(json, valueType); - } catch (IOException e) { - throw new SQLException("Exception deserializing JSON", e); - } - } - @Override public void nullSafeSet( PreparedStatement st, @@ -72,21 +53,28 @@ public void nullSafeSet( nullSafeSet(st, value, index); } - public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { - String value = rs.getString(names[0]).replace("\"value\"", "").replace("{:", "").replace("}", ""); - Object result = null; - if (valueType == null) { - throw new HibernateException("Value type not set."); - } - if (value != null && !value.equals("")) { - try { - result = OBJECT_MAPPER.readValue(value, valueType); - } catch (IOException e) { - throw new HibernateException("Exception deserializing value " + value, e); - } - } - return result; - } + @Override + public Object nullSafeGet( + ResultSet resultSet, + int index, + SharedSessionContractImplementor session, + Object owner + ) throws HibernateException, SQLException { + + String value = resultSet.getString(index).replace("\"value\"", "").replace("{:", "").replace("}", ""); + Object result = null; + if (valueType == null) { + throw new HibernateException("Value type not set."); + } + if (value != null && !value.equals("")) { + try { + result = OBJECT_MAPPER.readValue(value, valueType); + } catch (IOException e) { + throw new HibernateException("Exception deserializing value " + value, e); + } + } + return result; + } public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { StringWriter sw = new StringWriter();