diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..966ed1f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,30 @@ +name: Java CI with Maven + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Check Repository + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: maven + + - name: Build with Maven + working-directory: user-service + run: mvn -B clean verify + + - name: Upload test results + uses: actions/upload-artifact@v4 + with: + name: test-results + path: user-service/target/surefire-reports/ diff --git a/docker-compose.yml b/docker-compose.yml index 5c84ea7..ffff7c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -58,7 +58,6 @@ services: interval: 10s timeout: 10s retries: 5 - user-service: image: user-service:latest build: @@ -78,6 +77,13 @@ services: - KAFKA_BOOTSTRAP_SERVERS=kafka:9093 env_file: - .env - + redis: + image: redis:8.2.1 + restart: on-failure + ports: + - "6379:6379" + volumes: + - redis_data:/data volumes: pgdata: + redis_data: diff --git a/user-service/user-service-impl/pom.xml b/user-service/user-service-impl/pom.xml index 0587f22..f3f2f20 100644 --- a/user-service/user-service-impl/pom.xml +++ b/user-service/user-service-impl/pom.xml @@ -97,6 +97,8 @@ spring-boot-starter-hateoas + + org.springdoc @@ -132,5 +134,18 @@ spring-kafka + + + org.springframework.boot + spring-boot-starter-cache + 3.5.6 + + + + + org.springframework.boot + spring-boot-starter-data-redis + + - + \ No newline at end of file diff --git a/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/configuration/ConfigRedis.java b/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/configuration/ConfigRedis.java new file mode 100644 index 0000000..7220868 --- /dev/null +++ b/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/configuration/ConfigRedis.java @@ -0,0 +1,53 @@ +package ru.project.iakov.userservice.configuration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import ru.project.iakov.userservice.domain.entity.User; + +import java.time.Duration; + +@EnableCaching +@Configuration +public class ConfigRedis { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory, + ObjectMapper objectMapper) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(connectionFactory); + + redisTemplate.setKeySerializer(new StringRedisSerializer()); + + var serializer = new Jackson2JsonRedisSerializer<>(objectMapper,User.class); + redisTemplate.setValueSerializer(serializer); + + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + + @Bean + public CacheManager cacheManager(RedisConnectionFactory connectionFactory, + ObjectMapper objectMapper) { + var jsonSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, User.class); + + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(1)) + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())) + .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer)); + + return RedisCacheManager.builder(connectionFactory) + .cacheDefaults(config) + .transactionAware() + .build(); + } +} \ No newline at end of file diff --git a/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/service/impl/UserServiceImpl.java b/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/service/impl/UserServiceImpl.java index 2e04e57..b7f156a 100644 --- a/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/service/impl/UserServiceImpl.java +++ b/user-service/user-service-impl/src/main/java/ru/project/iakov/userservice/service/impl/UserServiceImpl.java @@ -2,6 +2,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ru.project.iakov.userservice.domain.entity.User; @@ -31,6 +33,10 @@ public class UserServiceImpl implements UserService { private final UserMapper userMapper; private final KafkaSender kafkaSender; + @Cacheable( + value = "user", + key = "#id" + ) @Override public UserResponse findById(UUID id) { User user = userRepository.findById(id) @@ -80,6 +86,10 @@ public UserResponse createUser(UserRequest userRequest) { return userMapper.toResponse(savedUser); } + @CacheEvict( + value = "user", + key = "#id" + ) @Override @Transactional public UserResponse updateUser(UUID id, UserRequest userRequest) { @@ -105,6 +115,10 @@ public UserResponse updateUser(UUID id, UserRequest userRequest) { return userMapper.toResponse(updatedUser); } + @CacheEvict( + value = "user", + key = "#id" + ) @Override @Transactional public void deleteUser(UUID id) { diff --git a/user-service/user-service-impl/src/main/resources/application.yml b/user-service/user-service-impl/src/main/resources/application.yml index 5484fa9..d33ae88 100644 --- a/user-service/user-service-impl/src/main/resources/application.yml +++ b/user-service/user-service-impl/src/main/resources/application.yml @@ -12,6 +12,12 @@ spring: properties: hibernate: format_sql: true + data: + redis: + host: ${SPRING_REDIS_HOST:localhost} + port: ${SPRING_REDIS_PORT:6379} + cache: + type: redis liquibase: change-log: classpath:db/changelog/db.changelog-master.yaml jackson: @@ -28,7 +34,6 @@ spring: producer: key-serializer: org.apache.kafka.common.serialization.StringSerializer value-serializer: org.springframework.kafka.support.serializer.JsonSerializer - logging: level: ru.project.iakov.userservice.kafka: INFO