You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by pt...@apache.org on 2021/12/23 14:21:45 UTC

[fineract] 01/01: Idempotency Support (FINERACT-1420)

This is an automated email from the ASF dual-hosted git repository.

ptuomola pushed a commit to branch idempotency
in repository https://gitbox.apache.org/repos/asf/fineract.git

commit d6b40d436d498b895623ac99ccbf3f5d43793105
Author: Vic Romero <vi...@fintecheando.mx>
AuthorDate: Mon Nov 1 23:29:08 2021 -0600

    Idempotency Support (FINERACT-1420)
---
 build.gradle                                       |   2 +
 docker-compose-idempotent.yml                      | 128 +++++++++++++++++++++
 fineract-provider/dependencies.gradle              |   2 +
 .../properties/basicauth/application.properties    |  15 +++
 .../savings/api/SavingsProductsApiResource.java    |   8 +-
 .../src/main/resources/logback-spring.xml          |   1 +
 6 files changed, 155 insertions(+), 1 deletion(-)

diff --git a/build.gradle b/build.gradle
index aa550fa..38e0d3f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -174,6 +174,8 @@ allprojects  {
             dependency "javax.annotation:javax.annotation-api:1.3.2"
             dependency "com.google.code.findbugs:jsr305:3.0.2"
             dependency "commons-codec:commons-codec:1.15"
+            //Idempotency Library
+            dependency "com.trendyol:Jdempotent-spring-boot-redis-starter:1.0.10"
 
             dependency ('org.flywaydb:flyway-core:7.15.0') {
                 // https://issues.apache.org/jira/browse/FINERACT-1172
diff --git a/docker-compose-idempotent.yml b/docker-compose-idempotent.yml
new file mode 100644
index 0000000..29a5eb0
--- /dev/null
+++ b/docker-compose-idempotent.yml
@@ -0,0 +1,128 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# NB: Travis CI (dist: bionic) supports up to v3.7
+# (unless we'd install a more recent version in .travis.yml)
+version: '3.7'
+networks:
+  app-tier:
+    driver: bridge
+services:
+  redis:
+    image: 'bitnami/redis:latest'
+    environment:
+      - REDIS_REPLICATION_MODE=master
+      - REDIS_PASSWORD=str0ng_passw0rd
+    networks:
+      - app-tier
+    ports:
+      - '6379:6379'
+  redis-slave:
+    image: 'bitnami/redis:latest'
+    environment:
+      - REDIS_REPLICATION_MODE=slave
+      - REDIS_MASTER_HOST=redis
+      - REDIS_MASTER_PASSWORD=str0ng_passw0rd
+      - REDIS_PASSWORD=str0ng_passw0rd
+    ports:
+      - '6379'
+    depends_on:
+      - redis
+    networks:
+      - app-tier
+  redis-slave-2:
+    image: 'bitnami/redis:latest'
+    environment:
+      - REDIS_REPLICATION_MODE=slave
+      - REDIS_MASTER_HOST=redis
+      - REDIS_MASTER_PASSWORD=str0ng_passw0rd
+      - REDIS_PASSWORD=str0ng_passw0rd
+    ports:
+      - '6379'
+    depends_on:
+      - redis
+    networks:
+      - app-tier
+  redis-sentinel:
+    image: 'bitnami/redis-sentinel:latest'
+    environment:
+      - REDIS_MASTER_PASSWORD=str0ng_passw0rd
+    depends_on:
+      - redis
+      - redis-slave
+      - redis-slave-2
+    ports:
+      - '26379:26379'
+    networks:
+      - app-tier
+  # Backend service
+  fineractmysql:
+    image: mysql:5.7
+    volumes:
+      - ./fineract-db/docker:/docker-entrypoint-initdb.d:Z,ro
+    restart: always
+    environment:
+      MYSQL_ROOT_PASSWORD: skdcnwauicn2ucnaecasdsajdnizucawencascdca
+    healthcheck:
+      test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost", "--password=skdcnwauicn2ucnaecasdsajdnizucawencascdca" ]
+      timeout: 10s
+      retries: 10
+    ports:
+      - "3306:3306"
+    networks:
+      - app-tier
+  fineract-server:
+    build:
+      context: .
+      target: fineract
+    ports:
+      - 8443:8443
+    networks:
+      - app-tier
+    depends_on:
+      - fineractmysql
+    environment:
+      - DRIVERCLASS_NAME=org.drizzle.jdbc.DrizzleDriver
+      - PROTOCOL=jdbc
+      - node_id=1
+      - SUB_PROTOCOL=mysql:thin
+      - fineract_tenants_driver=org.drizzle.jdbc.DrizzleDriver
+      - fineract_tenants_url=jdbc:mysql:thin://fineractmysql:3306/fineract_tenants
+      - fineract_tenants_uid=root
+      - fineract_tenants_pwd=skdcnwauicn2ucnaecasdsajdnizucawencascdca
+      - FINERACT_DEFAULT_TENANTDB_HOSTNAME=fineractmysql
+      - FINERACT_DEFAULT_TENANTDB_PORT=3306
+      - FINERACT_DEFAULT_TENANTDB_UID=root
+      - FINERACT_DEFAULT_TENANTDB_PWD=skdcnwauicn2ucnaecasdsajdnizucawencascdca
+      - FINERACT_DEFAULT_TENANTDB_CONN_PARAMS=
+
+  # Frontend service
+  community-app:
+    image: openmf/community-app:latest
+    container_name: mifos-ui
+    restart: always
+    ports:
+      - 9090:80
+    networks:
+      - app-tier
+
+# https://issues.apache.org/jira/browse/FINERACT-762
+# To use an altnerative JDBC driver (which is faster, but not allowed to be default in Apache distribution)
+# replace org.drizzle.jdbc.DrizzleDriver with com.mysql.jdbc.Driver in DRIVERCLASS_NAME and fineract_tenants_driver,
+# and remove ":thin:" from SUB_PROTOCOL and fineract_tenants_url.  Note that the mysql-connector-java-*.jar is already
+# bundled in the container by the Dockerfile, but just not used by default.
diff --git a/fineract-provider/dependencies.gradle b/fineract-provider/dependencies.gradle
index 2ab2467..019fe8c 100644
--- a/fineract-provider/dependencies.gradle
+++ b/fineract-provider/dependencies.gradle
@@ -69,6 +69,8 @@ dependencies {
 
             'com.google.cloud.sql:mysql-socket-factory-connector-j-8:1.4.0',
             'com.squareup.retrofit2:converter-gson',
+            'com.sun.activation:jakarta.activation:1.2.2',
+            'com.trendyol:Jdempotent-spring-boot-redis-starter:1.0.10'
             )
 
     implementation('org.springframework.boot:spring-boot-starter-jersey') {
diff --git a/fineract-provider/properties/basicauth/application.properties b/fineract-provider/properties/basicauth/application.properties
index 4a0e1dd..c9de2f2 100644
--- a/fineract-provider/properties/basicauth/application.properties
+++ b/fineract-provider/properties/basicauth/application.properties
@@ -30,3 +30,18 @@ management.info.git.mode=FULL
 
 # FINERACT-914
 server.forward-headers-strategy=framework
+
+# FINERACT-1420
+jdempotent.enable=false
+jdempotent.cryptography.algorithm=MD5
+jdempotent.cache.redis.database=9
+jdempotent.cache.redis.password=str0ng_passw0rd
+jdempotent.cache.redis.sentinelHostList=redis-sentinel
+jdempotent.cache.redis.sentinelPort=26379
+jdempotent.cache.redis.sentinelMasterName=mymaster
+jdempotent.cache.redis.expirationTimeHour=2
+jdempotent.cache.redis.dialTimeoutSecond=3
+jdempotent.cache.redis.readTimeoutSecond=3
+jdempotent.cache.redis.writeTimeoutSecond=3
+jdempotent.cache.redis.maxRetryCount=3
+jdempotent.cache.redis.expireTimeoutHour=84
diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java
index d01f4dc..485edaa 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/savings/api/SavingsProductsApiResource.java
@@ -18,6 +18,8 @@
  */
 package org.apache.fineract.portfolio.savings.api;
 
+import com.trendyol.jdempotent.core.annotation.JdempotentRequestPayload;
+import com.trendyol.jdempotent.core.annotation.JdempotentResource;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.media.ArraySchema;
@@ -31,9 +33,11 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
@@ -139,7 +143,9 @@ public class SavingsProductsApiResource {
     @RequestBody(required = true, content = @Content(schema = @Schema(implementation = SavingsProductsApiResourceSwagger.PostSavingsProductsRequest.class)))
     @ApiResponses({
             @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = SavingsProductsApiResourceSwagger.PostSavingsProductsResponse.class))) })
-    public String create(@Parameter(hidden = true) final String apiRequestBodyAsJson) {
+    @JdempotentResource(ttl = 30, ttlTimeUnit = TimeUnit.SECONDS)
+    public String create(@JdempotentRequestPayload @HeaderParam("x-idempotency-key") String xIdempotencyKeyHeader,
+            @Parameter(hidden = true) final String apiRequestBodyAsJson) {
 
         final CommandWrapper commandRequest = new CommandWrapperBuilder().createSavingProduct().withJson(apiRequestBodyAsJson).build();
 
diff --git a/fineract-provider/src/main/resources/logback-spring.xml b/fineract-provider/src/main/resources/logback-spring.xml
index 99e6e8c..b8d2043 100644
--- a/fineract-provider/src/main/resources/logback-spring.xml
+++ b/fineract-provider/src/main/resources/logback-spring.xml
@@ -39,4 +39,5 @@
     <!-- But these two INFO are still handy ;-) just to see when it's up and running -->
     <logger name="org.springframework.boot.web.embedded.tomcat.TomcatWebServer" level="info" />
     <logger name="org.apache.fineract.ServerApplication" level="info" />
+    <logger name="com.trendyol.jdempotent.core" level="DEBUG"/>
 </configuration>