Skip to content

Commit f89721d

Browse files
Fix merge conflict: use my latest CI steps
2 parents e8292f5 + e4ee77c commit f89721d

File tree

33 files changed

+681
-113
lines changed

33 files changed

+681
-113
lines changed

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,8 @@ jobs:
6868

6969
- name: Print Docker Compose logs
7070
if: always()
71-
run: docker compose logs
71+
<<<<<<< HEAD
72+
run: docker compose logs
73+
=======
74+
run: docker compose logs
75+
>>>>>>> e4ee77c6ec7ad9cca8bffe16bc2fe69ea1a5091c

README.md

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,39 @@
22

33
[![Maintainability](https://qlty.sh/badges/1d96f9b0-00d7-47ce-bd3a-f03a36f33f8c/maintainability.svg)](https://qlty.sh/gh/irinakomarchenko/projects/user-service-spring-Apache-Kafka)
44

5-
# User Service & Notification Service
5+
# user-service-cloud-architecture
6+
7+
### Микросервисная система управления пользователями и уведомлениями на Spring Boot, Kafka, Eureka, Docker и PostgreSQL.
68

79
**User Service** — микросервис на Spring Boot для управления пользователями (CRUD) и публикации событий о создании/удалении пользователей в Kafka.
8-
**Notification-service** — микросервис, который слушает события из Kafka и отправляет email-уведомления пользователям. Также предоставляет API для отправки email.
910

11+
**Notification-service** — микросервис, который слушает события из Kafka и отправляет email-уведомления пользователям. Также предоставляет API для отправки email.
12+
13+
**Gateway API** — микросервис, реализующий единый точку входа в систему (API Gateway на Spring Cloud Gateway). Маршрутизирует HTTP-запросы к нужным микросервисам.
14+
15+
**Discovery Server** — сервис регистрации и обнаружения (на базе Spring Cloud Eureka). Хранит реестр всех активных сервисов в системе, обеспечивает автоматическую маршрутизацию и отказоустойчивость.
16+
17+
**Config Server** — централизованный сервер конфигурации (Spring Cloud Config). Управляет конфигурационными файлами для всех микросервисов из единого репозитория.
18+
19+
**Kafka** — брокер сообщений (Apache Kafka), обеспечивает надёжную асинхронную передачу событий между сервисами.
20+
21+
**Mailhog** — сервис для перехвата и просмотра тестовых email-сообщений через web-интерфейс. Используется для локальной отладки отправки писем.
22+
23+
**PostgreSQL** — реляционная база данных для хранения информации о пользователях и событиях (используется user-service).
1024

1125
---
1226

1327
## Технологии
1428

1529
- Java 22
16-
- Spring Boot
17-
- Spring Web (REST API)
18-
- Spring Data JPA (встроенный Hibernate)
19-
- Spring Kafka (Kafka Producer)
30+
- Spring Boot (Spring Web, Spring Data JPA, Spring Kafka)
31+
- PostgreSQL (через Docker)
32+
- Apache Kafka (через Docker)
33+
- Spring Cloud (Gateway, Eureka Discovery, Config Server)
2034
- PostgreSQL (через Docker Compose)
21-
- Apache Kafka (интеграция через Spring Kafka)
22-
- SLF4J + Logback (логирование)
23-
- JUnit 5 + MockMvc (тестирование контроллеров и API)
24-
- Maven (сборка и зависимости)
25-
- Checkstyle (проверка стиля кода)
26-
- Lombok — (автогенерации геттеров/сеттеров)
35+
- JUnit 5, MockMvc (тестирование)
36+
- JLombok, SLF4J, Logback, Checkstyle
37+
- Docker (для контейнеризации сервисов)
2738
---
2839

2940
## Запуск проекта
@@ -57,11 +68,34 @@ mvn verify
5768

5869
### 6. Запустить приложение
5970

71+
#### Собрать артефакты (JAR-файлы) для каждого микросервиса:
6072

6173
```sh
6274
mvn clean package
63-
java -jar target/user-service-spring.jar
6475
```
76+
#### Запустить все сервисы и инфраструктуру с помощью Docker Compose:
77+
```sh
78+
docker compose up -d
79+
```
80+
Все сервисы (user-service, notification-service, gateway, discovery-server, config-server, kafka, postgres, mailhog) будут подняты как отдельные контейнеры.
81+
82+
#### Проверить статус контейнеров:
83+
```sh
84+
docker compose ps
85+
```
86+
87+
#### Остановить все сервисы:
88+
```sh
89+
docker compose down
90+
```
91+
92+
#### Для обновления jar-файлов после изменения кода пересоберите сервисы и перезапустите соответствующие контейнеры:
93+
```sh
94+
mvn clean package -DskipTests
95+
docker compose up --build -d
96+
```
97+
98+
6599

66100
### 7. Пример работы приложения
67101
![img_1.png](readme-resources/img_1.png)

circuit-breaker/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM openjdk:21-jdk-slim
2+
COPY target/circuit-breaker-1.0-SNAPSHOT.jar app.jar
3+
ENTRYPOINT ["java", "-jar", "/app.jar"]

circuit-breaker/pom.xml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>myuserservice</groupId>
8+
<artifactId>user-service-spring-Apache-Kafka</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
<artifactId>circuit-breaker</artifactId>
14+
<packaging>jar</packaging>
15+
16+
<dependencies>
17+
<dependency>
18+
<groupId>org.springframework.cloud</groupId>
19+
<artifactId>spring-cloud-starter-config</artifactId>
20+
</dependency>
21+
<dependency>
22+
<groupId>org.springframework.boot</groupId>
23+
<artifactId>spring-boot-starter-web</artifactId>
24+
</dependency>
25+
<dependency>
26+
<groupId>io.github.resilience4j</groupId>
27+
<artifactId>resilience4j-spring-boot3</artifactId>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.springframework.boot</groupId>
31+
<artifactId>spring-boot-starter-actuator</artifactId>
32+
</dependency>
33+
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-starter-webflux</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.springframework.cloud</groupId>
40+
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
41+
</dependency>
42+
<dependency>
43+
<groupId>org.projectlombok</groupId>
44+
<artifactId>lombok</artifactId>
45+
<scope>provided</scope>
46+
</dependency>
47+
</dependencies>
48+
49+
<build>
50+
<plugins>
51+
<plugin>
52+
<groupId>org.springframework.boot</groupId>
53+
<artifactId>spring-boot-maven-plugin</artifactId>
54+
<version>${spring-boot.version}</version>
55+
<executions>
56+
<execution>
57+
<goals>
58+
<goal>repackage</goal>
59+
</goals>
60+
</execution>
61+
</executions>
62+
</plugin>
63+
<plugin>
64+
<groupId>org.apache.maven.plugins</groupId>
65+
<artifactId>maven-compiler-plugin</artifactId>
66+
<version>3.10.1</version>
67+
<configuration>
68+
<source>${java.version}</source>
69+
<target>${java.version}</target>
70+
<compilerArgs>
71+
<arg>-parameters</arg>
72+
</compilerArgs>
73+
</configuration>
74+
</plugin>
75+
</plugins>
76+
</build>
77+
</project>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package circuitbreaker;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.web.client.RestTemplate;
7+
8+
@SpringBootApplication
9+
public class CircuitBreakerApplication {
10+
public static void main(String[] args) {
11+
SpringApplication.run(CircuitBreakerApplication.class, args);
12+
}
13+
14+
@Bean
15+
public RestTemplate restTemplate() {
16+
return new RestTemplate();
17+
}
18+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package circuitbreaker.controller;
2+
3+
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
4+
import org.springframework.beans.factory.annotation.Value;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.web.bind.annotation.*;
7+
import org.springframework.web.client.RestTemplate;
8+
9+
@RestController
10+
@RequestMapping("/api/cb")
11+
public class CircuitBreakerController {
12+
13+
private final RestTemplate restTemplate;
14+
15+
@Value("${user.service.url:http://user-service:8080/api/users}")
16+
private String userServiceUrl;
17+
18+
public CircuitBreakerController(RestTemplate restTemplate) {
19+
this.restTemplate = restTemplate;
20+
}
21+
22+
@GetMapping("/users")
23+
@CircuitBreaker(name = "myCircuitBreaker", fallbackMethod = "usersFallback")
24+
public ResponseEntity<String> getUsers() {
25+
String response = restTemplate.getForObject(userServiceUrl, String.class);
26+
return ResponseEntity.ok(response);
27+
}
28+
29+
public ResponseEntity<String> usersFallback(Exception e) {
30+
return ResponseEntity.ok("Fallback response: User service is currently unavailable.");
31+
}
32+
33+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
spring.application.name=circuit-breaker
2+
spring.config.import=configserver:http://config-server:8888/
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
spring.application.name=circuit-breaker
2+
server.port=8083
3+
4+
management.endpoints.web.exposure.include=*
5+
6+
eureka.client.service-url.defaultZone=http://discovery-server:8761/eureka
7+
eureka.instance.leaseRenewalIntervalInSeconds=10
8+
eureka.instance.leaseExpirationDurationInSeconds=60
9+
10+
resilience4j.circuitbreaker.instances.myCircuitBreaker.registerHealthIndicator=true
11+
resilience4j.circuitbreaker.instances.myCircuitBreaker.slidingWindowSize=5
12+
resilience4j.circuitbreaker.instances.myCircuitBreaker.minimumNumberOfCalls=3
13+
resilience4j.circuitbreaker.instances.myCircuitBreaker.failureRateThreshold=50
14+
resilience4j.circuitbreaker.instances.myCircuitBreaker.waitDurationInOpenState=5s
15+
16+
user.service.url=http://user-service:8081/api/users
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
server.port=8761
2+
server.address=0.0.0.0
3+
4+
management.endpoints.web.exposure.include=*
5+
6+
eureka.client.register-with-eureka=false
7+
eureka.client.fetch-registry=false

config-repo/gateway-api.properties

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
spring.application.name=gateway-api
2+
server.port=8080
3+
4+
management.endpoints.web.exposure.include=*
5+
6+
logging.level.org.springframework.cloud.gateway=DEBUG
7+
8+
spring.cloud.gateway.discovery.locator.enabled=true
9+
spring.cloud.gateway.discovery.locator.lower-case-service-id=true
10+
11+
eureka.client.service-url.defaultZone=http://discovery-server:8761/eureka

0 commit comments

Comments
 (0)