Skip to content
Merged
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
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,19 @@ jobs:
- name: Build ${{ matrix.service }}
run: mvn clean install -DskipTests
working-directory: ./${{ matrix.service }}

ci-complete:
runs-on: ubuntu-latest
needs: [detect-changes, build-services]
if: always() # This forces the job to run even if build-services is skipped!
steps:
- name: Check build status
run: |
# If changes were detected but the build failed
if [[ "${{ needs.build-services.result }}" == "failure" || "${{ needs.build-services.result }}" == "cancelled" ]]; then
echo "Build failed or was cancelled."
exit 1
fi

# If everything passed or was safely skipped
echo "All touched services built successfully (or no changes detected)."
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ public class User {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Column(unique = true)
@Column(name = "email", unique = true)
private String email;

@Column(name = "password")
private String password;
}
}
52 changes: 17 additions & 35 deletions compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
context: ./userService
dockerfile: Dockerfile.dev
deploy:
replicas: 2
replicas: 1
volumes:
- ./userService/target:/app/target
- ./userService/src:/app/src
Expand Down Expand Up @@ -36,7 +36,7 @@ services:
context: ./authService
dockerfile: Dockerfile.dev
deploy:
replicas: 2
replicas: 1
volumes:
- ./authService/target:/app/target
- ./authService/src:/app/src
Expand Down Expand Up @@ -75,7 +75,7 @@ services:
- ~/.m2:/root/.m2
restart: always
deploy:
replicas: 2
replicas: 1
depends_on:
eureka:
condition: service_healthy
Expand Down Expand Up @@ -145,7 +145,8 @@ services:
cpus: "0.6"
environment:
- JAVA_TOOL_OPTIONS=-XX:+UseContainerSupport -Xms128m -Xmx200m

env_file:
- .env
gateway:
build:
context: ./gateway
Expand Down Expand Up @@ -202,54 +203,35 @@ services:
retries: 5
start_period: 15s

zookeeper:
image: confluentinc/cp-zookeeper:7.5.0
container_name: zookeeper
restart: always
ports:
- "2181:2181"
mem_limit: 500m
cpus: "0.6"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
volumes:
- zookeeper-data:/var/lib/zookeeper/data
- zookeeper-logs:/var/lib/zookeeper/log
networks:
- micro-net
healthcheck:
test: [ "CMD-SHELL", "echo srvr | nc localhost 2181 | grep -q 'Mode: standalone'" ]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s


kafka:
image: confluentinc/cp-kafka:7.5.0
container_name: kafka
restart: always
ports:
- "19092:29092"
depends_on:
zookeeper:
condition: service_healthy
mem_limit: 1.2g
cpus: "2.0"
healthcheck:
test: [ "CMD-SHELL", "kafka-topics --bootstrap-server localhost:29092 --list" ]
test: ["CMD-SHELL", "kafka-topics --bootstrap-server kafka:29092 --list"]
interval: 10s
timeout: 10s
retries: 5
start_period: 15s
retries: 10
start_period: 30s
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:19092,CONTROLLER://kafka:29093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:19092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT,CONTROLLER:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:29093
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true"
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
volumes:
- kafka-data:/var/lib/kafka/data
networks:
Expand Down
4 changes: 0 additions & 4 deletions configServer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
Expand Down
8 changes: 7 additions & 1 deletion configServer/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ server.port=8888
spring.application.name=config-server
eureka.client.service-url.defaultZone=http://eureka:8761/eureka
spring.profiles.active=native
spring.cloud.config.server.native.search-locations=classpath:/configs
spring.cloud.config.server.native.search-locations=classpath:/configs
management.endpoints.web.exposure.include=health,info,prometheus,metrics
management.endpoint.health.show-details=always
management.server.port=${MANAGEMENT_PORT}
management.tracing.sampling.probability=1.0
# 1.0 for dev and testing, adjust for production like 0.1 or 0.01 to reduce overhead
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ server.port=0
#Eureka management
spring.cloud.config.enabled=false

# Flyway
spring.flyway.enabled=true
spring.flyway.baseline-on-migrate=true

# JPA - let Flyway manage schema
spring.jpa.hibernate.ddl-auto=validate

#Database management
spring.datasource.url=${DATABASE_URL}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ server.port=0
#Eureka management
spring.cloud.config.enabled=false


# Flyway
spring.flyway.enabled=true
spring.flyway.baseline-on-migrate=true

# JPA - let Flyway manage schema
spring.jpa.hibernate.ddl-auto=validate

#Database management
spring.datasource.url=${DATABASE_URL}
spring.datasource.username=${POSTGRES_USER}
Expand Down
14 changes: 8 additions & 6 deletions load-test/src/test/scala/simulation/UserServiceSimulation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ class UserServiceSimulation extends Simulation {
// ─── Feeders ──────────────────────────────────────────────────────────────

val createUserFeeder = Iterator.continually(Map(
"name" -> s"user_${Random.alphanumeric.take(6).mkString}",
"email" -> s"user_${Random.alphanumeric.take(8).mkString}@test.com"
"firstName" -> s"user_${Random.alphanumeric.take(6).mkString}",
"lastName" -> s"last_${Random.alphanumeric.take(4).mkString}",
"email" -> s"user_${Random.alphanumeric.take(8).mkString}@test.com",
"password" -> "password123"
))

// Infinite circular feeder — never runs out
Expand Down Expand Up @@ -61,7 +63,7 @@ class UserServiceSimulation extends Simulation {
http("POST /users")
.post("/users")
.body(StringBody(
"""{"name": "#{name}", "email": "#{email}"}"""
"""{"firstName": "#{firstName}", "lastName": "#{lastName}", "email": "#{email}", "password": "#{password}"}"""
)).asJson
.check(status.is(200))
.check(responseTimeInMillis.lte(2000))
Expand All @@ -76,7 +78,7 @@ class UserServiceSimulation extends Simulation {
http("PUT /users/{id}")
.put("/users/#{userId}")
.body(StringBody(
"""{"name": "#{name}_updated", "email": "#{email}"}"""
"""{"firstName": "#{firstName}_updated", "lastName": "#{lastName}_updated", "email": "#{email}"}"""
)).asJson
.check(status.in(200, 404))
.check(responseTimeInMillis.lte(2000))
Expand Down Expand Up @@ -123,7 +125,7 @@ class UserServiceSimulation extends Simulation {
http("POST create user")
.post("/users")
.body(StringBody(
"""{"name": "#{name}", "email": "#{email}"}"""
"""{"firstName": "#{firstName}", "lastName": "#{lastName}", "email": "#{email}", "password": "#{password}"}"""
)).asJson
.check(status.is(200))
.check(jsonPath("$.id").saveAs("newUserId"))
Expand All @@ -133,7 +135,7 @@ class UserServiceSimulation extends Simulation {
http("PUT update user")
.put("/users/#{newUserId}")
.body(StringBody(
"""{"name": "#{name}_updated", "email": "#{email}"}"""
"""{"firstName": "#{firstName}_updated", "lastName": "#{lastName}_updated", "email": "#{email}"}"""
)).asJson
.check(status.in(200, 404))
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ datasources:
access: proxy
url: http://prometheus:9090
isDefault: false
editable: false
editable: false
14 changes: 11 additions & 3 deletions observability/prometheus-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ global:
evaluation_interval: 15s

scrape_configs:
- job_name: 'eureka'
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']

- job_name: 'eureka-services'
metrics_path: '/actuator/prometheus'
eureka_sd_configs:
- server: http://eureka:8761/eureka
relabel_configs:
- source_labels: [__meta_eureka_app_name]
target_label: application
- source_labels: [__meta_eureka_instance_host_name]
target_label: instance
- source_labels: [__meta_eureka_app_instance_host_name]
target_label: instance
- source_labels: [__address__]
regex: '(.+):\d+'
target_label: __address__
replacement: '${1}:8081'
1 change: 0 additions & 1 deletion userService/Dockerfile.dev
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ WORKDIR /app

# Copy pom.xml and download dependencies first (cached layer)
COPY pom.xml .
RUN mvn dependency:go-offline

# Copy the rest of your source code
COPY src ./src
Expand Down
8 changes: 8 additions & 0 deletions userService/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ public class User {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Column(unique = true)
@Column(name = "email", unique = true)
private String email;

@Column(name = "password")
private String password;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE IF NOT EXISTS users (
id BIGSERIAL PRIMARY KEY,
first_name VARCHAR(255) NOT NULL,
last_name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL
);
Loading