Skip to content

Commit

Permalink
Feat/#98 Log 서버, (Project, App) 서버 분리 (#100)
Browse files Browse the repository at this point in the history
* config: init logbat_meta project

* refactor: copy Project, Apps code

* refactor: Project endpoint 수정

- projects/{projectId} 로 통일

* refactor: App endpoint 수정

- projects/apps -> /projects/{projectId}/apps

* refactor: 미사용 메서드 삭제

* refactor: copy and 개선 App, Project 테스트코드

* refactor: delete App, Project code in logbat project

- logbat_meta 프로젝트로 이전

* refactor: JPA 관련 코드 제거

* refactor: AsyncLogProcessor 생성자 개선

- this 참조 추가
- database poolsize debug로그 추가

* fix: 데이터베이스 poolsize 직접 지정

* feat: AppJDBCRepository 추가

- JDBC Template를 사용한 데이터베이스 조회 구현

* refactor: JPA 설정 제거

* fix: 에러를 반환하지 않고 빈값을 반환하도록 수정

* test: 도메인 분리로 불가능한 테스트 수정

* config: Nginx 설정 변경

* fix: 서버 주소 변경

* config: 변경된 도메인 적용

* refactor: 변수명 변경

- l -> id
  • Loading branch information
LuizyHub authored Aug 21, 2024
1 parent 9b98482 commit fea0ff3
Show file tree
Hide file tree
Showing 51 changed files with 949 additions and 685 deletions.
6 changes: 4 additions & 2 deletions logbat/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,16 @@ repositories {
dependencies {
// SpringBoot Web
implementation 'org.springframework.boot:spring-boot-starter-web'
// SpringBoot JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// SpringBoot Validation
implementation 'org.springframework.boot:spring-boot-starter-validation'
// Caffeine
implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
// SpringBoot Cache
implementation 'org.springframework.boot:spring-boot-starter-cache'
// Spring AOP
implementation 'org.springframework.boot:spring-boot-starter-aop'
// JDBC
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
// Lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public long saveLog(CreateLogServiceRequest request) {
String data = request.data();
LocalDateTime timestamp = request.timestamp();

Long appId = appService.getAppByToken(request.appKey()).id();
Long appId = appService.getAppIdByToken(request.appKey());

Log log = Log.of(appId, level, data, timestamp);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ public AsyncLogProcessor(@Value("${jdbc.async.timeout}") Long timeout,
throw new IllegalArgumentException("DataSource is null");
}
int poolSize = ((HikariDataSource) dataSource).getMaximumPoolSize();
log.debug("Creating AsyncLogProcessor with pool size: {}", poolSize);

// use 50% of the pool size for the follower thread pool
followerExecutor = Executors.newFixedThreadPool(poolSize * 5 / 10);
this.followerExecutor = Executors.newFixedThreadPool(poolSize * 5 / 10);
this.defaultTimeout = Objects.requireNonNullElse(timeout, 2000L);
this.defaultBulkSize = Objects.requireNonNullElse(bulkSize, 100);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,73 +1,30 @@
package info.logbat.domain.project.application;

import info.logbat.domain.project.domain.App;
import info.logbat.domain.project.domain.Project;
import info.logbat.domain.project.domain.enums.AppType;
import info.logbat.domain.project.presentation.payload.response.AppCommonResponse;
import info.logbat.domain.project.repository.AppJpaRepository;
import info.logbat.domain.project.repository.ProjectJpaRepository;
import java.util.List;
import java.util.UUID;
import info.logbat.domain.project.repository.AppRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional
@RequiredArgsConstructor
@CacheConfig(cacheNames = {"app"})
public class AppService {

private static final String APP_NOT_FOUND_MESSAGE = "앱을 찾을 수 없습니다.";

private final AppJpaRepository appRepository;
private final ProjectJpaRepository projectRepository;
private final AppRepository appRepository;

public AppCommonResponse createApp(Long projectId, String appTypeStr) {
Project project = getProject(projectId);
AppType appType = AppType.from(appTypeStr);
return AppCommonResponse.from(appRepository.save(App.of(project, appType)));
}

@Transactional(readOnly = true)
@Cacheable(key = "#token")
public AppCommonResponse getAppByToken(String token) {
UUID tokenUUID = UUID.fromString(token);
App app = appRepository.findByAppKey(tokenUUID)
.orElseThrow(() -> new IllegalArgumentException(APP_NOT_FOUND_MESSAGE));
return AppCommonResponse.from(app);
}

@Transactional(readOnly = true)
public AppCommonResponse getAppById(Long id) {
App app = appRepository.findById(id)
public Long getAppIdByToken(String token) {
return appRepository.getAppIdByToken(token)
.orElseThrow(() -> new IllegalArgumentException(APP_NOT_FOUND_MESSAGE));
return AppCommonResponse.from(app);
}

@Transactional(readOnly = true)
public List<AppCommonResponse> getAppsByProjectId(Long projectId) {
List<App> apps = appRepository.findByProject_Id(projectId);
return apps.stream().map(AppCommonResponse::from).toList();
}

public Long deleteApp(Long projectId, Long appId) {
App app = appRepository.findByProject_IdAndId(projectId, appId)
.orElseThrow(() -> new IllegalArgumentException(APP_NOT_FOUND_MESSAGE));
appRepository.delete(app);
evictAppCache(app.getAppKey().toString());
return app.getId();
}

@CacheEvict(key = "#token")
public void evictAppCache(String token) {
}
// TODO: Implement cache eviction

private Project getProject(Long id) {
return projectRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("프로젝트를 찾을 수 없습니다."));
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package info.logbat.domain.project.repository;

import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
@RequiredArgsConstructor
public class AppRepository {

private final JdbcTemplate jdbcTemplate;

public Optional<Long> getAppIdByToken(String token) {
try {
String sql = "SELECT id FROM apps WHERE app_key = UNHEX(REPLACE(?, '-', ''))";
Long id = jdbcTemplate.queryForObject(sql, Long.class, token);
return Optional.ofNullable(id);
}
catch (Exception e) {
return Optional.empty();
}
}
}
12 changes: 4 additions & 8 deletions logbat/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ spring:
username: root
password:
driver-class-name: com.mysql.cj.jdbc.Driver

jpa:
hibernate:
ddl-auto: create
hikari:
maximum-pool-size: 10

---
spring:
Expand All @@ -35,7 +33,5 @@ spring:
username: root
password:
driver-class-name: com.mysql.cj.jdbc.Driver

jpa:
hibernate:
ddl-auto: none
hikari:
maximum-pool-size: 10
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
import info.logbat.domain.log.application.LogService;
import info.logbat.domain.log.presentation.LogController;
import info.logbat.domain.project.application.AppService;
import info.logbat.domain.project.application.ProjectService;
import info.logbat.domain.project.presentation.AppController;
import info.logbat.domain.project.presentation.ProjectController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
Expand All @@ -18,8 +15,7 @@
/*
* 이후 테스트 하려면 Controller에 대해 controllers에 추가하고, ControllerTestSupport를 상속받아 테스트를 진행하시면 됩니다.
*/
@WebMvcTest(controllers = {LogController.class, ProjectController.class, AppController.class,
CountTestController.class})
@WebMvcTest(controllers = {LogController.class, CountTestController.class})
@ActiveProfiles("test")
public abstract class ControllerTestSupport {

Expand All @@ -32,9 +28,6 @@ public abstract class ControllerTestSupport {
@MockBean
protected LogService logService;

@MockBean
protected ProjectService projectService;

@MockBean
protected AppService appService;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
package info.logbat.domain.log.application;

import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import info.logbat.domain.log.application.payload.request.CreateLogServiceRequest;
import info.logbat.domain.log.repository.LogRepository;
import info.logbat.domain.project.domain.App;
import info.logbat.domain.project.domain.Project;
import info.logbat.domain.project.domain.enums.AppType;
import info.logbat.domain.project.repository.AppJpaRepository;
import info.logbat.domain.project.repository.ProjectJpaRepository;
import java.time.LocalDateTime;
import java.util.UUID;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -28,18 +23,12 @@ class LogServiceTest {
@Autowired
private LogService logService;

@Autowired
private LogRepository logRepository;

@Autowired
private ProjectJpaRepository projectJpaRepository;

@Autowired
private AppJpaRepository appJpaRepository;

@DisplayName("Log를 저장할 수 있다.")
@Disabled("APP, PROJECT domain이 없어서 테스트가 불가능합니다.")
@Test
void saveLog() {
throw new UnsupportedOperationException("아직 구현되지 않았습니다.");
/*
// given
String 프로젝트_이름 = "테스트_프로젝트";
Project 프로젝트 = Project.from(프로젝트_이름);
Expand All @@ -63,6 +52,7 @@ void saveLog() {
// when & then
assertThatCode(() -> logService.saveLog(요청_DTO))
.doesNotThrowAnyException();
*/
}

@DisplayName("존재하지 않는 Application Key로 Log를 저장할 수 없다.")
Expand Down
Loading

0 comments on commit fea0ff3

Please sign in to comment.