Skip to content

Commit

Permalink
RediSearch Connection 관리 #127
Browse files Browse the repository at this point in the history
Merge pull request #127 from team-crews/refactor/#125-manage-redisearch-connection
  • Loading branch information
jongmee authored Nov 30, 2024
2 parents b113d4d + 126a452 commit fd34ffa
Show file tree
Hide file tree
Showing 15 changed files with 64 additions and 90 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@ jobs:
sudo chmod +x /usr/local/bin/docker-compose
docker pull ${{ secrets.DOCKER_PROD_SERVER_IMAGE_NAME }}
docker rm -f crews-server
docker stop --time=3 crews-server
docker rm crews-server
docker-compose up crews-server -d
docker image prune -f
Expand Down
2 changes: 1 addition & 1 deletion docker-compose-client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ services:
SPRING_DATASOURCE_PASSWORD: "1234"
SPRING_DATA_REDIS_HOST: "redis"
SPRING_DATA_REDIS_PORT: "6379"
REDS-STACK_HOST: "redis-stack"
REDIS-STACK_HOST: "redis-stack"
REDIS-STACK_PORT: "6379"

db:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.server.crews.external.config;

import com.redis.lettucemod.RedisModulesClient;
import com.redis.lettucemod.api.StatefulRedisModulesConnection;
import com.redis.lettucemod.spring.RedisModulesAutoConfiguration;
import io.lettuce.core.RedisURI;
import java.time.Duration;
Expand All @@ -12,11 +11,11 @@

@Configuration
@EnableAutoConfiguration(exclude = RedisModulesAutoConfiguration.class)
public class RedisStackConfig {
public class RediSearchConfig {
private final String host;
private final String port;

public RedisStackConfig(@Value("${redis-stack.host}") String host, @Value("${redis-stack.port}") String port) {
public RediSearchConfig(@Value("${redis-stack.host}") String host, @Value("${redis-stack.port}") String port) {
this.host = host;
this.port = port;
}
Expand All @@ -30,10 +29,4 @@ public RedisModulesClient redisModulesClient() {
.build();
return RedisModulesClient.create(redisURI);
}

@Bean
public StatefulRedisModulesConnection<String, String> redisModulesConnection(
RedisModulesClient redisModulesClient) {
return redisModulesClient.connect();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.server.crews.external.config;

import com.redis.lettucemod.RedisModulesClient;
import com.redis.lettucemod.api.StatefulRedisModulesConnection;
import com.redis.lettucemod.api.sync.RedisModulesCommands;
import jakarta.annotation.PreDestroy;
import org.springframework.stereotype.Component;

@Component
public class RediSearchConnection {
private final StatefulRedisModulesConnection<String, String> redisModulesConnection;

public RediSearchConnection(RedisModulesClient redisModulesClient) {
this.redisModulesConnection = redisModulesClient.connect();
}

public RedisModulesCommands<String, String> getCommands() {
return redisModulesConnection.sync();
}

@PreDestroy
public void close() {
redisModulesConnection.close();
}
}
14 changes: 11 additions & 3 deletions src/main/java/com/server/crews/global/CustomLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import org.slf4j.MDC;

public class CustomLogger {
private static final String PACKAGE_NAME = "com.server.crews";
private static final int STACK_TRACE_STORE_LIMIT = 8;

private final Logger logger;

public CustomLogger(Class<?> clazz) {
Expand All @@ -31,14 +32,21 @@ public void error(Exception e) {

private String extractPackageStackTrace(Exception e) {
StringBuilder stackTraceBuilder = new StringBuilder();
int count = 0;
for (StackTraceElement element : e.getStackTrace()) {
if (element.getClassName().startsWith(PACKAGE_NAME)) {
stackTraceBuilder.append(element).append("\n");
stackTraceBuilder.append(element).append(" ");
count++;
if (exceedStoreLimit(count)) {
break;
}
}
return stackTraceBuilder.toString();
}

private boolean exceedStoreLimit(int count) {
return count >= STACK_TRACE_STORE_LIMIT;
}

public void info(String var1, Object... var2) {
logger.info(var1, var2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import com.server.crews.recruitment.domain.SelectiveQuestion;
import com.server.crews.recruitment.repository.RecruitmentRepository;
import com.server.crews.recruitment.service.SimpleRedisRecruitmentSearchService;
import com.server.crews.recruitment.service.RedisStackRecruitmentSearchService;
import com.server.crews.recruitment.service.RediSearchRecruitmentSearchService;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand All @@ -37,7 +37,7 @@ public class DatabaseInitializer implements ApplicationRunner {
private final ApplicantRepository applicantRepository;
private final ApplicationRepository applicationRepository;
private final SimpleRedisRecruitmentSearchService simpleRedisRecruitmentSearchService;
private final RedisStackRecruitmentSearchService redisStackRecruitmentSearchService;
private final RediSearchRecruitmentSearchService rediSearchRecruitmentSearchService;

@Override
public void run(ApplicationArguments args) {
Expand Down Expand Up @@ -72,8 +72,8 @@ public void run(ApplicationArguments args) {
recruitment.close();
recruitmentRepository.save(recruitment);
simpleRedisRecruitmentSearchService.saveRecruitment(recruitment);
redisStackRecruitmentSearchService.createIndex();
redisStackRecruitmentSearchService.saveRecruitment(recruitment);
rediSearchRecruitmentSearchService.createIndex();
rediSearchRecruitmentSearchService.saveRecruitment(recruitment);

Applicant kh = new Applicant("[email protected]", passwordEncoder.encode("test-password"));
Applicant lkh = new Applicant("[email protected]", passwordEncoder.encode("test-password"));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.server.crews.recruitment.repository;

import com.server.crews.recruitment.domain.NarrativeQuestion;
import com.server.crews.recruitment.domain.Section;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface NarrativeQuestionRepository extends JpaRepository<NarrativeQuestion, Long> {
List<NarrativeQuestion> findAllBySectionIn(List<Section> sections);
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
package com.server.crews.recruitment.repository;

import com.server.crews.recruitment.domain.Section;
import com.server.crews.recruitment.domain.SelectiveQuestion;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface SelectiveQuestionRepository extends JpaRepository<SelectiveQuestion, Long> {
@Query("""
select s from SelectiveQuestion s
left join fetch s.choices
where s.section in :sections
""")
List<SelectiveQuestion> findAllWithChoicesInSections(@Param("sections") List<Section> sections);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public class RecruitmentService {

private final RecruitmentRepository recruitmentRepository;
private final RecruitmentDetailsLoader recruitmentDetailsLoader;
private final RedisStackRecruitmentSearchService recruitmentSearchService;
private final RediSearchRecruitmentSearchService recruitmentSearchService;
private final AdministratorRepository administratorRepository;
private final ApplicationRepository applicationRepository;
private final ApplicationEventPublisher eventPublisher;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.server.crews.recruitment.service;

import com.redis.lettucemod.api.StatefulRedisModulesConnection;
import com.redis.lettucemod.api.sync.RedisModulesCommands;
import com.redis.lettucemod.search.CreateOptions;
import com.redis.lettucemod.search.Document;
import com.redis.lettucemod.search.Field;
import com.redis.lettucemod.search.Limit;
import com.redis.lettucemod.search.SearchOptions;
import com.redis.lettucemod.search.SearchResults;
import com.server.crews.global.CustomLogger;
import com.server.crews.external.config.RediSearchConnection;
import com.server.crews.recruitment.domain.Recruitment;
import io.lettuce.core.RedisCommandExecutionException;
import java.time.LocalDateTime;
Expand All @@ -19,21 +18,19 @@

@Repository
@RequiredArgsConstructor
public class RedisStackRecruitmentSearchService implements RecruitmentSearchService {
public class RediSearchRecruitmentSearchService implements RecruitmentSearchService {
private static final String INDEX_KEY = "recruitment:";
private static final String INDEX_NAME = "recruitment_idx";
private static final ZoneId seoulZoneId = ZoneId.of("Asia/Seoul");
private static final CustomLogger customLogger = new CustomLogger(RedisStackRecruitmentSearchService.class);

private final StatefulRedisModulesConnection<String, String> redisModulesConnection;
private final RediSearchConnection rediSearchConnection;

@Override
public void saveRecruitment(Recruitment recruitment) {
String recruitmentKey = INDEX_KEY + recruitment.getId();
RedisModulesCommands<String, String> commands = redisModulesConnection.sync();
RedisModulesCommands<String, String> commands = rediSearchConnection.getCommands();
commands.hset(recruitmentKey, "title", recruitment.getTitle());
commands.hset(recruitmentKey, "deadline", String.valueOf(getUnixTimestamp(recruitment.getDeadline())));

}

private static long getUnixTimestamp(LocalDateTime dateTime) {
Expand All @@ -42,7 +39,7 @@ private static long getUnixTimestamp(LocalDateTime dateTime) {

@Override
public List<String> findRecruitmentTitlesByKeyword(String keyword, int limit) {
RedisModulesCommands<String, String> commands = redisModulesConnection.sync();
RedisModulesCommands<String, String> commands = rediSearchConnection.getCommands();

SearchOptions searchOptions = new SearchOptions();
searchOptions.setLimit(new Limit(0, limit));
Expand All @@ -61,7 +58,7 @@ public List<String> findRecruitmentTitlesByKeyword(String keyword, int limit) {
운영 서버에서는 사용하지 말 것.
*/
public void createIndex() {
RedisModulesCommands<String, String> commands = redisModulesConnection.sync();
RedisModulesCommands<String, String> commands = rediSearchConnection.getCommands();
if (!isIndexExists(commands)) {
CreateOptions createOptions = new CreateOptions.Builder().prefix(INDEX_KEY).build();
commands.ftCreate(INDEX_NAME, createOptions,
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/config
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package com.server.crews.recruitment.repository;

import static com.server.crews.fixture.QuestionFixture.INTRODUCTION_QUESTION;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import com.server.crews.auth.domain.Administrator;
import com.server.crews.environ.repository.RepositoryTest;
import com.server.crews.recruitment.domain.NarrativeQuestion;
import com.server.crews.recruitment.domain.Recruitment;
import com.server.crews.recruitment.domain.Section;
import com.server.crews.recruitment.repository.NarrativeQuestionRepository;
import jakarta.validation.ConstraintViolationException;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -20,21 +18,6 @@ class NarrativeQuestionRepositoryTest extends RepositoryTest {
@Autowired
private NarrativeQuestionRepository narrativeQuestionRepository;

@Test
@DisplayName("섹션들의 모든 서술형 문항을 조회한다.")
void findAllBySectionIn() {
// given
Administrator publisher = createDefaultAdmin();
Recruitment recruitment = createDefaultRecruitment(publisher);
List<Section> sections = recruitment.getOrderedSections();

// when
List<NarrativeQuestion> narrativeQuestions = narrativeQuestionRepository.findAllBySectionIn(sections);

// then
assertThat(narrativeQuestions).hasSize(2);
}

@Test
@DisplayName("글자 수 제한은 최대 1500까지 가능하다.")
void saveWithValidation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@

import static com.server.crews.fixture.QuestionFixture.CHOICES;
import static com.server.crews.fixture.QuestionFixture.STRENGTH_QUESTION;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;

import com.server.crews.auth.domain.Administrator;
import com.server.crews.environ.repository.RepositoryTest;
import com.server.crews.recruitment.domain.Recruitment;
import com.server.crews.recruitment.domain.Section;
import com.server.crews.recruitment.domain.SelectiveQuestion;
import com.server.crews.recruitment.repository.SelectiveQuestionRepository;
import jakarta.validation.ConstraintViolationException;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -22,25 +19,6 @@ class SelectiveQuestionRepositoryTest extends RepositoryTest {
@Autowired
private SelectiveQuestionRepository selectiveQuestionRepository;

@Test
@DisplayName("선택형 문항을 조회할 때 선택지들도 함께 조회한다.")
void findAllWithChoicesBySection() {
// given
Administrator publisher = createDefaultAdmin();
Recruitment recruitment = createDefaultRecruitment(publisher);

// when
List<SelectiveQuestion> selectiveQuestions = selectiveQuestionRepository.findAllWithChoicesInSections(
recruitment.getOrderedSections());

// then
assertAll(
() -> assertThat(selectiveQuestions).hasSize(2),
() -> assertThat(selectiveQuestions).flatExtracting(SelectiveQuestion::getChoices)
.hasSize(6)
);
}

@Test
@DisplayName("선택형 문항의 최소, 최대 선택 개수는 1이상 10이하의 값이다.")
void saveWithValidation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class RedisStackRecruitmentSearchServiceTest {
class RediSearchRecruitmentSearchServiceTest {

@Autowired
private RedisStackRecruitmentSearchService redisStackRecruitmentSearchService;
private RediSearchRecruitmentSearchService rediSearchRecruitmentSearchService;

@Autowired
private RedisModulesClient redisSearchClient;
Expand All @@ -47,7 +47,7 @@ void tearDown() {
@DisplayName("모집 공고 검색에 대한 인덱스를 생성한다.")
void createIndex() {
// when
redisStackRecruitmentSearchService.createIndex();
rediSearchRecruitmentSearchService.createIndex();

// then
List<Object> recruitmentIndexInfo = commands.ftInfo("recruitment_idx");
Expand All @@ -62,23 +62,23 @@ void createIndex() {
@DisplayName("모집 공고 제목을 텍스트 검색한다.")
void saveAndSearch() {
// given
redisStackRecruitmentSearchService.createIndex();
rediSearchRecruitmentSearchService.createIndex();

redisStackRecruitmentSearchService.saveRecruitment(
rediSearchRecruitmentSearchService.saveRecruitment(
new Recruitment(1l, DEFAULT_CODE, "멋쟁이사자처럼 서강대학교 99기 아기사자 모집", DEFAULT_DESCRIPTION,
LocalDateTime.of(2030, 10, 5, 0, 0, 0), null,
List.of()));
redisStackRecruitmentSearchService.saveRecruitment(
rediSearchRecruitmentSearchService.saveRecruitment(
new Recruitment(2l, DEFAULT_CODE, "대박 멋진 멋쟁이사자처럼 서강대학교 100기 아기사자 모집", DEFAULT_DESCRIPTION,
LocalDateTime.of(2030, 11, 5, 0, 0, 0), null,
List.of()));
redisStackRecruitmentSearchService.saveRecruitment(
rediSearchRecruitmentSearchService.saveRecruitment(
new Recruitment(3l, DEFAULT_CODE, "CEOS 백엔드 99기 모집", DEFAULT_DESCRIPTION,
LocalDateTime.of(2030, 11, 5, 0, 0, 0), null,
List.of()));

// when
List<String> results = redisStackRecruitmentSearchService.findRecruitmentTitlesByKeyword("멋쟁이", 5);
List<String> results = rediSearchRecruitmentSearchService.findRecruitmentTitlesByKeyword("멋쟁이", 5);

// then
assertThat(results).hasSize(2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

class SimpleRedisRedisStackRecruitmentSearchServiceTest extends CacheStoreTest {
class SimpleRedisRediSearchRecruitmentSearchServiceTest extends CacheStoreTest {

@Autowired
private SimpleRedisRecruitmentSearchService simpleRedisRecruitmentSearchService;
Expand Down

0 comments on commit fd34ffa

Please sign in to comment.