Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
version: '3.8'

services:
# Redis for rate limiting and caching
redis:
image: redis:7-alpine
container_name: smartdrive-redis
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 30s
timeout: 10s
retries: 3

# Eureka Service Discovery
eureka-server:
image: springcloud/eureka:latest
container_name: smartdrive-eureka
ports:
- "8761:8761"
environment:
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8761/actuator/health"]
interval: 30s
timeout: 10s
retries: 3

# API Gateway
api-gateway:
build: .
container_name: smartdrive-gateway
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- REDIS_HOST=redis
- REDIS_PORT=6379
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
- GATEWAY_INTERNAL_SECRET=gateway-secret-2024
- GATEWAY_SIGNATURE_SECRET=signature-secret-2024
depends_on:
redis:
condition: service_healthy
eureka-server:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3

# Auth Service (placeholder)
auth-service:
image: openjdk:17-alpine
container_name: smartdrive-auth
ports:
- "8085:8085"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
depends_on:
eureka-server:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8085/actuator/health"]
interval: 30s
timeout: 10s
retries: 3

# User Service (placeholder)
user-service:
image: openjdk:17-alpine
container_name: smartdrive-user
ports:
- "8081:8081"
environment:
- SPRING_PROFILES_ACTIVE=docker
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka/
depends_on:
eureka-server:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/actuator/health"]
interval: 30s
timeout: 10s
retries: 3

# Prometheus for monitoring
prometheus:
image: prom/prometheus:latest
container_name: smartdrive-prometheus
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--storage.tsdb.retention.time=200h'
- '--web.enable-lifecycle'
depends_on:
- api-gateway

# Grafana for visualization
grafana:
image: grafana/grafana:latest
container_name: smartdrive-grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
- ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources
depends_on:
- prometheus

volumes:
redis_data:
grafana_data:
47 changes: 47 additions & 0 deletions monitoring/prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
global:
scrape_interval: 15s
evaluation_interval: 15s

rule_files:
# - "first_rules.yml"
# - "second_rules.yml"

scrape_configs:
# Prometheus itself
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']

# API Gateway
- job_name: 'api-gateway'
static_configs:
- targets: ['api-gateway:8080']
metrics_path: '/actuator/prometheus'
scrape_interval: 10s
scrape_timeout: 5s

# Auth Service
- job_name: 'auth-service'
static_configs:
- targets: ['auth-service:8085']
metrics_path: '/actuator/prometheus'
scrape_interval: 15s

# User Service
- job_name: 'user-service'
static_configs:
- targets: ['user-service:8081']
metrics_path: '/actuator/prometheus'
scrape_interval: 15s

# Redis
- job_name: 'redis'
static_configs:
- targets: ['redis:6379']

# Eureka Service Discovery
- job_name: 'eureka'
static_configs:
- targets: ['eureka-server:8761']
metrics_path: '/actuator/prometheus'
scrape_interval: 30s
118 changes: 118 additions & 0 deletions src/main/java/com/smartdrive/gateway/config/CircuitBreakerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.smartdrive.gateway.config;

import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
import org.springframework.cloud.client.circuitbreaker.Customizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

/**
* Circuit Breaker configuration for API Gateway
* Provides fault tolerance and resilience patterns
*/
@Configuration
@Slf4j
public class CircuitBreakerConfig {

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(10)
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofSeconds(10))
.permittedNumberOfCallsInHalfOpenState(5)
.slowCallRateThreshold(50)
.slowCallDurationThreshold(Duration.ofSeconds(2))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(3))
.build())
.build());
}

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> authServiceCustomizer() {
return factory -> factory.configure(builder -> builder
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(20)
.failureRateThreshold(30)
.waitDurationInOpenState(Duration.ofSeconds(30))
.permittedNumberOfCallsInHalfOpenState(10)
.slowCallRateThreshold(30)
.slowCallDurationThreshold(Duration.ofSeconds(1))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(2))
.build()), "auth-service-circuit-breaker");
}

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> userServiceCustomizer() {
return factory -> factory.configure(builder -> builder
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(15)
.failureRateThreshold(40)
.waitDurationInOpenState(Duration.ofSeconds(20))
.permittedNumberOfCallsInHalfOpenState(8)
.slowCallRateThreshold(40)
.slowCallDurationThreshold(Duration.ofSeconds(1.5))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(2.5))
.build()), "user-service-cb");
}

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> fileStorageCustomizer() {
return factory -> factory.configure(builder -> builder
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(25)
.failureRateThreshold(25)
.waitDurationInOpenState(Duration.ofSeconds(60))
.permittedNumberOfCallsInHalfOpenState(15)
.slowCallRateThreshold(20)
.slowCallDurationThreshold(Duration.ofSeconds(5))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(10))
.build()), "file-storage-circuit-breaker");
}

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> aiServiceCustomizer() {
return factory -> factory.configure(builder -> builder
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(30)
.failureRateThreshold(20)
.waitDurationInOpenState(Duration.ofSeconds(45))
.permittedNumberOfCallsInHalfOpenState(20)
.slowCallRateThreshold(15)
.slowCallDurationThreshold(Duration.ofSeconds(10))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(15))
.build()), "ai-service-circuit-breaker");
}

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> searchServiceCustomizer() {
return factory -> factory.configure(builder -> builder
.circuitBreakerConfig(CircuitBreakerConfig.custom()
.slidingWindowSize(20)
.failureRateThreshold(35)
.waitDurationInOpenState(Duration.ofSeconds(25))
.permittedNumberOfCallsInHalfOpenState(12)
.slowCallRateThreshold(30)
.slowCallDurationThreshold(Duration.ofSeconds(3))
.build())
.timeLimiterConfig(TimeLimiterConfig.custom()
.timeoutDuration(Duration.ofSeconds(5))
.build()), "search-service-circuit-breaker");
}
}
Loading